[Scummvm-git-logs] scummvm master -> 2ecc1dcd41d6900720e7be5db50b3535e87f77b6

dreammaster dreammaster at scummvm.org
Sat Feb 27 05:30:51 UTC 2021


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
1a8ae27b58 AGS: Move game & spriteset into Globals
2ecc1dcd41 AGS: Change some Strings to const char *


Commit: 1a8ae27b589290536adbaa975f87b5bacfb396dd
    https://github.com/scummvm/scummvm/commit/1a8ae27b589290536adbaa975f87b5bacfb396dd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-02-26T21:28:53-08:00

Commit Message:
AGS: Move game & spriteset into Globals

Changed paths:
  A engines/ags/globals.cpp
  A engines/ags/globals.h
  R engines/ags/engine/globals.cpp
  R engines/ags/engine/globals.h
    engines/ags/ags.cpp
    engines/ags/engine/ac/audioclip.cpp
    engines/ags/engine/ac/button.cpp
    engines/ags/engine/ac/character.cpp
    engines/ags/engine/ac/characterinfo_engine.cpp
    engines/ags/engine/ac/dialog.cpp
    engines/ags/engine/ac/display.cpp
    engines/ags/engine/ac/draw.cpp
    engines/ags/engine/ac/drawingsurface.cpp
    engines/ags/engine/ac/dynamicsprite.cpp
    engines/ags/engine/ac/dynobj/cc_audioclip.cpp
    engines/ags/engine/ac/dynobj/cc_character.cpp
    engines/ags/engine/ac/dynobj/scriptdrawingsurface.cpp
    engines/ags/engine/ac/event.cpp
    engines/ags/engine/ac/file.cpp
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/ac/gamestate.cpp
    engines/ags/engine/ac/gamestate.h
    engines/ags/engine/ac/global_audio.cpp
    engines/ags/engine/ac/global_button.cpp
    engines/ags/engine/ac/global_character.cpp
    engines/ags/engine/ac/global_debug.cpp
    engines/ags/engine/ac/global_dialog.cpp
    engines/ags/engine/ac/global_display.cpp
    engines/ags/engine/ac/global_drawingsurface.cpp
    engines/ags/engine/ac/global_dynamicsprite.cpp
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/ac/global_gui.cpp
    engines/ags/engine/ac/global_hotspot.cpp
    engines/ags/engine/ac/global_inventoryitem.cpp
    engines/ags/engine/ac/global_label.cpp
    engines/ags/engine/ac/global_object.cpp
    engines/ags/engine/ac/global_overlay.cpp
    engines/ags/engine/ac/global_palette.cpp
    engines/ags/engine/ac/global_room.cpp
    engines/ags/engine/ac/global_screen.cpp
    engines/ags/engine/ac/global_slider.cpp
    engines/ags/engine/ac/global_string.cpp
    engines/ags/engine/ac/global_textbox.cpp
    engines/ags/engine/ac/global_viewframe.cpp
    engines/ags/engine/ac/gui.cpp
    engines/ags/engine/ac/guicontrol.cpp
    engines/ags/engine/ac/guiinv.cpp
    engines/ags/engine/ac/inventoryitem.cpp
    engines/ags/engine/ac/invwindow.cpp
    engines/ags/engine/ac/label.cpp
    engines/ags/engine/ac/listbox.cpp
    engines/ags/engine/ac/mouse.cpp
    engines/ags/engine/ac/object.cpp
    engines/ags/engine/ac/overlay.cpp
    engines/ags/engine/ac/parser.cpp
    engines/ags/engine/ac/properties.cpp
    engines/ags/engine/ac/region.cpp
    engines/ags/engine/ac/room.cpp
    engines/ags/engine/ac/roomobject.cpp
    engines/ags/engine/ac/screen.cpp
    engines/ags/engine/ac/speech.cpp
    engines/ags/engine/ac/sprite.cpp
    engines/ags/engine/ac/statobj/agsstaticobject.cpp
    engines/ags/engine/ac/string.cpp
    engines/ags/engine/ac/sys_events.cpp
    engines/ags/engine/ac/system.cpp
    engines/ags/engine/ac/textbox.cpp
    engines/ags/engine/ac/translation.cpp
    engines/ags/engine/ac/viewframe.cpp
    engines/ags/engine/ac/walkablearea.cpp
    engines/ags/engine/debugging/debug.cpp
    engines/ags/engine/device/mousew32.cpp
    engines/ags/engine/font/fonts_engine.cpp
    engines/ags/engine/game/game_init.cpp
    engines/ags/engine/game/savegame.cpp
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/engine/gfx/graphicsdriver.h
    engines/ags/engine/gui/cscidialog.cpp
    engines/ags/engine/gui/gui_engine.cpp
    engines/ags/engine/gui/guidialog.cpp
    engines/ags/engine/gui/mylistbox.cpp
    engines/ags/engine/gui/mypushbutton.cpp
    engines/ags/engine/gui/newcontrol.cpp
    engines/ags/engine/main/config.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/engine/main/engine_setup.cpp
    engines/ags/engine/main/engine_setup.h
    engines/ags/engine/main/game_file.cpp
    engines/ags/engine/main/game_run.cpp
    engines/ags/engine/main/game_start.cpp
    engines/ags/engine/main/graphics_mode.cpp
    engines/ags/engine/main/quit.cpp
    engines/ags/engine/main/update.cpp
    engines/ags/engine/media/audio/audio.cpp
    engines/ags/engine/media/audio/soundcache.cpp
    engines/ags/engine/platform/linux/acpllnx.cpp
    engines/ags/engine/platform/windows/acplwin.cpp
    engines/ags/engine/script/cc_instance.cpp
    engines/ags/engine/script/script.cpp
    engines/ags/engine/util/library_scummvm.h
    engines/ags/events.cpp
    engines/ags/game_scanner.cpp
    engines/ags/module.mk
    engines/ags/music.cpp
    engines/ags/plugins/agsplugin.cpp
    engines/ags/shared/ac/common.cpp
    engines/ags/shared/ac/gamesetupstruct.cpp
    engines/ags/shared/ac/mousecursor.cpp
    engines/ags/shared/ac/spritecache.h
    engines/ags/shared/font/fonts.cpp
    engines/ags/shared/game/main_game_file.cpp
    engines/ags/shared/game/roomstruct.h
    engines/ags/shared/gui/guibutton.cpp
    engines/ags/shared/gui/guilistbox.cpp
    engines/ags/shared/gui/guimain.cpp
    engines/ags/shared/gui/guislider.cpp


diff --git a/engines/ags/ags.cpp b/engines/ags/ags.cpp
index f5405041ab..4784175dd4 100644
--- a/engines/ags/ags.cpp
+++ b/engines/ags/ags.cpp
@@ -38,7 +38,7 @@
 #include "ags/lib/std/set.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/game.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/engine/ac/gamesetup.h"
 #include "ags/engine/ac/gamestate.h"
 #include "ags/engine/ac/room.h"
diff --git a/engines/ags/engine/ac/audioclip.cpp b/engines/ags/engine/ac/audioclip.cpp
index 19b4c41630..545a45f85d 100644
--- a/engines/ags/engine/ac/audioclip.cpp
+++ b/engines/ags/engine/ac/audioclip.cpp
@@ -31,7 +31,7 @@
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
+
 extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
 extern CCAudioChannel ccDynamicAudio;
 
diff --git a/engines/ags/engine/ac/button.cpp b/engines/ags/engine/ac/button.cpp
index e6e1267e95..06a7d39a5b 100644
--- a/engines/ags/engine/ac/button.cpp
+++ b/engines/ags/engine/ac/button.cpp
@@ -31,17 +31,16 @@
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/engine/gui/animatingguibutton.h"
 #include "ags/shared/gui/guimain.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
 extern ViewStruct *views;
 
 // *** BUTTON FUNCTIONS
@@ -53,7 +52,7 @@ void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat)
 	int guin = butt->ParentId;
 	int objn = butt->Id;
 
-	if ((view < 1) || (view > game.numviews))
+	if ((view < 1) || (view > _GP(game).numviews))
 		quit("!AnimateButton: invalid view specified");
 	view--;
 
@@ -106,7 +105,7 @@ void Button_SetText(GUIButton *butt, const char *newtx) {
 }
 
 void Button_SetFont(GUIButton *butt, int newFont) {
-	if ((newFont < 0) || (newFont >= game.numfonts))
+	if ((newFont < 0) || (newFont >= _GP(game).numfonts))
 		quit("!Button.Font: invalid font number.");
 
 	if (butt->Font != newFont) {
@@ -163,8 +162,8 @@ void Button_SetNormalGraphic(GUIButton *guil, int slotn) {
 		guil->CurrentImage = slotn;
 	guil->Image = slotn;
 	// update the clickable area to the same size as the graphic
-	guil->Width = game.SpriteInfos[slotn].Width;
-	guil->Height = game.SpriteInfos[slotn].Height;
+	guil->Width = _GP(game).SpriteInfos[slotn].Width;
+	guil->Height = _GP(game).SpriteInfos[slotn].Height;
 
 	guis_need_update = 1;
 	FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index 7db64928e7..5056a07da8 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -61,7 +61,6 @@
 #include "ags/engine/main/update.h"
 #include "ags/shared/ac/spritecache.h"
 #include "ags/shared/util/string_compat.h"
-//include <math.h>
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/engine/script/runtimescriptvalue.h"
 #include "ags/engine/ac/dynobj/cc_character.h"
@@ -70,24 +69,22 @@
 #include "ags/shared/gfx/gfx_def.h"
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/ac/movelist.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
 extern int displayed_room, starting_room;
 extern RoomStruct thisroom;
 extern MoveList *mls;
 extern ViewStruct *views;
 extern RoomObject *objs;
 extern ScriptInvItem scrInv[MAX_INV];
-extern SpriteCache spriteset;
 extern Bitmap *walkable_areas_temp;
 extern IGraphicsDriver *gfxDriver;
 extern Bitmap **actsps;
@@ -139,7 +136,7 @@ void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addInd
 
 	int charid = chaa->index_id;
 
-	if (game.options[OPT_DUPLICATEINV] == 0) {
+	if (_GP(game).options[OPT_DUPLICATEINV] == 0) {
 		// Ensure it is only in the list once
 		for (ee = 0; ee < charextra[charid].invorder_count; ee++) {
 			if (charextra[charid].invorder[ee] == inum) {
@@ -221,7 +218,7 @@ void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat, int
 }
 
 void Character_ChangeRoomAutoPosition(CharacterInfo *chaa, int room, int newPos) {
-	if (chaa->index_id != game.playercharacter) {
+	if (chaa->index_id != _GP(game).playercharacter) {
 		quit("!Character.ChangeRoomAutoPosition can only be used with the player character.");
 	}
 
@@ -252,7 +249,7 @@ void Character_ChangeRoom(CharacterInfo *chaa, int room, int x, int y) {
 
 void Character_ChangeRoomSetLoop(CharacterInfo *chaa, int room, int x, int y, int direction) {
 
-	if (chaa->index_id != game.playercharacter) {
+	if (chaa->index_id != _GP(game).playercharacter) {
 		// NewRoomNPC
 		if ((x != SCR_NO_VALUE) && (y != SCR_NO_VALUE)) {
 			chaa->x = x;
@@ -291,7 +288,7 @@ void Character_ChangeRoomSetLoop(CharacterInfo *chaa, int room, int x, int y, in
 void Character_ChangeView(CharacterInfo *chap, int vii) {
 	vii--;
 
-	if ((vii < 0) || (vii >= game.numviews))
+	if ((vii < 0) || (vii >= _GP(game).numviews))
 		quit("!ChangeCharacterView: invalid view number specified");
 
 	// if animating, but not idle view, give warning message
@@ -377,7 +374,7 @@ DirectionalLoop GetDirectionalLoop(CharacterInfo *chinfo, int x_diff, int y_diff
 void FaceDirectionalLoop(CharacterInfo *char1, int direction, int blockingStyle) {
 	// Change facing only if the desired direction is different
 	if (direction != char1->loop) {
-		if ((game.options[OPT_TURNTOFACELOC] != 0) &&
+		if ((_GP(game).options[OPT_TURNTOFACELOC] != 0) &&
 		        (in_enters_screen == 0)) {
 			const int no_diagonal = useDiagonal(char1);
 			const int highestLoopForTurning = no_diagonal != 1 ? kDirLoop_Last : kDirLoop_LastOrthogonal;
@@ -459,7 +456,7 @@ void Character_FollowCharacter(CharacterInfo *chaa, CharacterInfo *tofollow, int
 	if ((eagerness < 0) || (eagerness > 250))
 		quit("!FollowCharacterEx: invalid eagerness: must be 0-250");
 
-	if ((chaa->index_id == game.playercharacter) && (tofollow != nullptr) &&
+	if ((chaa->index_id == _GP(game).playercharacter) && (tofollow != nullptr) &&
 	        (tofollow->room != chaa->room))
 		quit("!FollowCharacterEx: you cannot tell the player character to follow a character in another room");
 
@@ -543,7 +540,7 @@ int Character_IsCollidingWithObject(CharacterInfo *chin, ScriptObject *objid) {
 	        (o2y >= o1y - 8) &&
 	        (o2y <= o1y + game_to_data_coord(objHeight))) {
 		// the character's feet are on the object
-		if (game.options[OPT_PIXPERFECT] == 0)
+		if (_GP(game).options[OPT_PIXPERFECT] == 0)
 			return 1;
 		// check if they're on a transparent bit of the object
 		int stxp = data_to_game_coord(o2x - o1x);
@@ -582,8 +579,8 @@ void Character_LockView(CharacterInfo *chap, int vii) {
 
 void Character_LockViewEx(CharacterInfo *chap, int vii, int stopMoving) {
 
-	if ((vii < 1) || (vii > game.numviews)) {
-		quitprintf("!SetCharacterView: invalid view number (You said %d, max is %d)", vii, game.numviews);
+	if ((vii < 1) || (vii > _GP(game).numviews)) {
+		quitprintf("!SetCharacterView: invalid view number (You said %d, max is %d)", vii, _GP(game).numviews);
 	}
 	vii--;
 
@@ -622,7 +619,7 @@ void Character_LockViewAlignedEx(CharacterInfo *chap, int vii, int loop, int ali
 		quit("!SetCharacterLoop: character has invalid old view number");
 
 	int sppic = views[chap->view].loops[chap->loop].frames[chap->frame].pic;
-	int leftSide = data_to_game_coord(chap->x) - game.SpriteInfos[sppic].Width / 2;
+	int leftSide = data_to_game_coord(chap->x) - _GP(game).SpriteInfos[sppic].Width / 2;
 
 	Character_LockViewEx(chap, vii, stopMoving);
 
@@ -632,7 +629,7 @@ void Character_LockViewAlignedEx(CharacterInfo *chap, int vii, int loop, int ali
 	chap->loop = loop;
 	chap->frame = 0;
 	int newpic = views[chap->view].loops[chap->loop].frames[chap->frame].pic;
-	int newLeft = data_to_game_coord(chap->x) - game.SpriteInfos[newpic].Width / 2;
+	int newLeft = data_to_game_coord(chap->x) - _GP(game).SpriteInfos[newpic].Width / 2;
 	int xdiff = 0;
 
 	if (align & kMAlignLeft)
@@ -640,7 +637,7 @@ void Character_LockViewAlignedEx(CharacterInfo *chap, int vii, int loop, int ali
 	else if (align & kMAlignHCenter)
 		xdiff = 0;
 	else if (align & kMAlignRight)
-		xdiff = (leftSide + game.SpriteInfos[sppic].Width) - (newLeft + game.SpriteInfos[newpic].Width);
+		xdiff = (leftSide + _GP(game).SpriteInfos[sppic].Width) - (newLeft + _GP(game).SpriteInfos[newpic].Width);
 	else
 		quit("!SetCharacterViewEx: invalid alignment type specified");
 
@@ -697,7 +694,7 @@ void Character_LoseInventory(CharacterInfo *chap, ScriptInvItem *invi) {
 
 	int charid = chap->index_id;
 
-	if ((chap->inv[inum] == 0) || (game.options[OPT_DUPLICATEINV] > 0)) {
+	if ((chap->inv[inum] == 0) || (_GP(game).options[OPT_DUPLICATEINV] > 0)) {
 		int xx, tt;
 		for (xx = 0; xx < charextra[charid].invorder_count; xx++) {
 			if (charextra[charid].invorder[xx] == inum) {
@@ -773,7 +770,7 @@ void Character_SetAsPlayer(CharacterInfo *chaa) {
 	// But only on versions > 2.61. The relevant entry in the 2.62 changelog is:
 	//  - Fixed SetPlayerCharacter to do nothing at all if you pass the current
 	//    player character to it (previously it was resetting the inventory layout)
-	if ((loaded_game_file_version > kGameVersion_261) && (game.playercharacter == chaa->index_id))
+	if ((loaded_game_file_version > kGameVersion_261) && (_GP(game).playercharacter == chaa->index_id))
 		return;
 
 	setup_player_character(chaa->index_id);
@@ -1048,14 +1045,14 @@ void Character_RunInteraction(CharacterInfo *chaa, int mood) {
 
 int Character_GetProperty(CharacterInfo *chaa, const char *property) {
 
-	return get_int_property(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property);
+	return get_int_property(_GP(game).charProps[chaa->index_id], play.charProps[chaa->index_id], property);
 
 }
 void Character_GetPropertyText(CharacterInfo *chaa, const char *property, char *bufer) {
-	get_text_property(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property, bufer);
+	get_text_property(_GP(game).charProps[chaa->index_id], play.charProps[chaa->index_id], property, bufer);
 }
 const char *Character_GetTextProperty(CharacterInfo *chaa, const char *property) {
-	return get_text_property_dynamic_string(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property);
+	return get_text_property_dynamic_string(_GP(game).charProps[chaa->index_id], play.charProps[chaa->index_id], property);
 }
 
 bool Character_SetProperty(CharacterInfo *chaa, const char *property, int value) {
@@ -1080,7 +1077,7 @@ void Character_SetActiveInventory(CharacterInfo *chaa, ScriptInvItem *iit) {
 	if (iit == nullptr) {
 		chaa->activeinv = -1;
 
-		if (chaa->index_id == game.playercharacter) {
+		if (chaa->index_id == _GP(game).playercharacter) {
 
 			if (GetCursorMode() == MODE_USE)
 				set_cursor_mode(0);
@@ -1095,7 +1092,7 @@ void Character_SetActiveInventory(CharacterInfo *chaa, ScriptInvItem *iit) {
 
 	chaa->activeinv = iit->id;
 
-	if (chaa->index_id == game.playercharacter) {
+	if (chaa->index_id == _GP(game).playercharacter) {
 		// if it's the player character, update mouse cursor
 		update_inv_cursor(iit->id);
 		set_cursor_mode(MODE_USE);
@@ -1153,7 +1150,7 @@ int Character_GetBlinkView(CharacterInfo *chaa) {
 
 void Character_SetBlinkView(CharacterInfo *chaa, int vii) {
 
-	if (((vii < 2) || (vii > game.numviews)) && (vii != -1))
+	if (((vii < 2) || (vii > _GP(game).numviews)) && (vii != -1))
 		quit("!SetCharacterBlinkView: invalid view number");
 
 	chaa->blinkview = vii - 1;
@@ -1243,7 +1240,7 @@ int Character_GetIdleView(CharacterInfo *chaa) {
 }
 
 int Character_GetIInventoryQuantity(CharacterInfo *chaa, int index) {
-	if ((index < 1) || (index >= game.numinvitems))
+	if ((index < 1) || (index >= _GP(game).numinvitems))
 		quitprintf("!Character.InventoryQuantity: invalid inventory index %d", index);
 
 	return chaa->inv[index];
@@ -1257,7 +1254,7 @@ int Character_HasInventory(CharacterInfo *chaa, ScriptInvItem *invi) {
 }
 
 void Character_SetIInventoryQuantity(CharacterInfo *chaa, int index, int quant) {
-	if ((index < 1) || (index >= game.numinvitems))
+	if ((index < 1) || (index >= _GP(game).numinvitems))
 		quitprintf("!Character.InventoryQuantity: invalid inventory index %d", index);
 
 	if ((quant < 0) || (quant > 32000))
@@ -1312,7 +1309,7 @@ int Character_GetIgnoreWalkbehinds(CharacterInfo *chaa) {
 }
 
 void Character_SetIgnoreWalkbehinds(CharacterInfo *chaa, int yesorno) {
-	if (game.options[OPT_BASESCRIPTAPI] >= kScriptAPI_v350)
+	if (_GP(game).options[OPT_BASESCRIPTAPI] >= kScriptAPI_v350)
 		debug_script_warn("IgnoreWalkbehinds is not recommended for use, consider other solutions");
 	chaa->flags &= ~CHF_NOWALKBEHINDS;
 	if (yesorno)
@@ -1473,7 +1470,7 @@ void Character_SetSpeechColor(CharacterInfo *chaa, int ncol) {
 }
 
 void Character_SetSpeechAnimationDelay(CharacterInfo *chaa, int newDelay) {
-	if (game.options[OPT_GLOBALTALKANIMSPD] != 0) {
+	if (_GP(game).options[OPT_GLOBALTALKANIMSPD] != 0) {
 		debug_script_warn("Character.SpeechAnimationDelay cannot be set when global speech animation speed is enabled");
 		return;
 	}
@@ -1492,7 +1489,7 @@ void Character_SetSpeechView(CharacterInfo *chaa, int vii) {
 		return;
 	}
 
-	if ((vii < 1) || (vii > game.numviews))
+	if ((vii < 1) || (vii > _GP(game).numviews))
 		quit("!SetCharacterSpeechView: invalid view number");
 
 	chaa->talkview = vii - 1;
@@ -1516,7 +1513,7 @@ int Character_GetThinkView(CharacterInfo *chaa) {
 }
 
 void Character_SetThinkView(CharacterInfo *chaa, int vii) {
-	if (((vii < 2) || (vii > game.numviews)) && (vii != -1))
+	if (((vii < 2) || (vii > _GP(game).numviews)) && (vii != -1))
 		quit("!SetCharacterThinkView: invalid view number");
 
 	chaa->thinkview = vii - 1;
@@ -1612,7 +1609,7 @@ int Character_GetSpeakingFrame(CharacterInfo *chaa) {
 int turnlooporder[8] = {0, 6, 1, 7, 3, 5, 2, 4};
 
 void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims) {
-	CharacterInfo *chin = &game.chars[chac];
+	CharacterInfo *chin = &_GP(game).chars[chac];
 	if (chin->room != displayed_room)
 		quit("!MoveCharacter: character not in current room");
 
@@ -1667,7 +1664,7 @@ void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims)
 	set_route_move_speed(move_speed_x, move_speed_y);
 	set_color_depth(8);
 	int mslot = find_route(charX, charY, tox, toy, prepare_walkable_areas(chac), chac + CHMLSOFFS, 1, ignwal);
-	set_color_depth(game.GetColorDepth());
+	set_color_depth(_GP(game).GetColorDepth());
 	if (mslot > 0) {
 		chin->walking = mslot;
 		mls[mslot].direct = ignwal;
@@ -1772,7 +1769,7 @@ void fix_player_sprite(MoveList *cmls, CharacterInfo *chinf) {
 
 	const int useloop = GetDirectionalLoop(chinf, xpmove, ypmove);
 
-	if ((game.options[OPT_ROTATECHARS] == 0) || ((chinf->flags & CHF_NOTURNING) != 0)) {
+	if ((_GP(game).options[OPT_ROTATECHARS] == 0) || ((chinf->flags & CHF_NOTURNING) != 0)) {
 		chinf->loop = useloop;
 		return;
 	}
@@ -1798,19 +1795,19 @@ void fix_player_sprite(MoveList *cmls, CharacterInfo *chinf) {
 int has_hit_another_character(int sourceChar) {
 
 	// if the character who's moving doesn't Bitmap *, don't bother checking
-	if (game.chars[sourceChar].flags & CHF_NOBLOCKING)
+	if (_GP(game).chars[sourceChar].flags & CHF_NOBLOCKING)
 		return -1;
 
-	for (int ww = 0; ww < game.numcharacters; ww++) {
-		if (game.chars[ww].on != 1) continue;
-		if (game.chars[ww].room != displayed_room) continue;
+	for (int ww = 0; ww < _GP(game).numcharacters; ww++) {
+		if (_GP(game).chars[ww].on != 1) continue;
+		if (_GP(game).chars[ww].room != displayed_room) continue;
 		if (ww == sourceChar) continue;
-		if (game.chars[ww].flags & CHF_NOBLOCKING) continue;
+		if (_GP(game).chars[ww].flags & CHF_NOBLOCKING) continue;
 
 		if (is_char_on_another(sourceChar, ww, nullptr, nullptr)) {
 			// we are now overlapping character 'ww'
-			if ((game.chars[ww].walking) &&
-			        ((game.chars[ww].flags & CHF_AWAITINGMOVE) == 0))
+			if ((_GP(game).chars[ww].walking) &&
+			        ((_GP(game).chars[ww].flags & CHF_AWAITINGMOVE) == 0))
 				return ww;
 		}
 
@@ -1832,8 +1829,8 @@ int doNextCharMoveStep(CharacterInfo *chi, int &char_index, CharacterExtras *che
 	ntf = has_hit_another_character(char_index);
 	if (ntf >= 0) {
 		chi->walkwait = 30;
-		if (game.chars[ntf].walkspeed < 5)
-			chi->walkwait += (5 - game.chars[ntf].walkspeed) * 5;
+		if (_GP(game).chars[ntf].walkspeed < 5)
+			chi->walkwait += (5 - _GP(game).chars[ntf].walkspeed) * 5;
 		// we are now waiting for the other char to move, so
 		// make sure he doesn't stop for us too
 
@@ -1850,7 +1847,7 @@ int doNextCharMoveStep(CharacterInfo *chi, int &char_index, CharacterExtras *che
 			chi->x = xwas;
 			chi->y = ywas;
 		}
-		debug_script_log("%s: Bumped into %s, waiting for them to move", chi->scrname, game.chars[ntf].scrname);
+		debug_script_log("%s: Bumped into %s, waiting for them to move", chi->scrname, _GP(game).chars[ntf].scrname);
 		return 1;
 	}
 	return 0;
@@ -1968,7 +1965,7 @@ void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int
 }
 
 int is_valid_character(int newchar) {
-	if ((newchar < 0) || (newchar >= game.numcharacters)) return 0;
+	if ((newchar < 0) || (newchar >= _GP(game).numcharacters)) return 0;
 	return 1;
 }
 
@@ -2046,8 +2043,8 @@ int wantMoveNow(CharacterInfo *chi, CharacterExtras *chex) {
 }
 
 void setup_player_character(int charid) {
-	game.playercharacter = charid;
-	playerchar = &game.chars[charid];
+	_GP(game).playercharacter = charid;
+	playerchar = &_GP(game).chars[charid];
 	_sc_PlayerCharPtr = ccGetObjectHandleFromAddress((char *)playerchar);
 	if (loaded_game_file_version < kGameVersion_270) {
 		ccAddExternalDynamicObject("player", playerchar, &ccDynamicCharacter);
@@ -2056,7 +2053,7 @@ void setup_player_character(int charid) {
 
 void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept, int noidleoverride, int direction, int sframe) {
 
-	if ((chap->view < 0) || (chap->view > game.numviews)) {
+	if ((chap->view < 0) || (chap->view > _GP(game).numviews)) {
 		quitprintf("!AnimateCharacter: you need to set the view number first\n"
 		           "(trying to animate '%s' using loop %d. View is currently %d).", chap->name, loopn, chap->view + 1);
 	}
@@ -2120,35 +2117,35 @@ Bitmap *GetCharacterImage(int charid, int *isFlipped) {
 			return actsps[charid + MAX_ROOM_OBJECTS];
 		}
 	}
-	CharacterInfo *chin = &game.chars[charid];
+	CharacterInfo *chin = &_GP(game).chars[charid];
 	int sppic = views[chin->view].loops[chin->loop].frames[chin->frame].pic;
-	return spriteset[sppic];
+	return _GP(spriteset)[sppic];
 }
 
 CharacterInfo *GetCharacterAtScreen(int xx, int yy) {
 	int hsnum = GetCharIDAtScreen(xx, yy);
 	if (hsnum < 0)
 		return nullptr;
-	return &game.chars[hsnum];
+	return &_GP(game).chars[hsnum];
 }
 
 CharacterInfo *GetCharacterAtRoom(int x, int y) {
 	int hsnum = is_pos_on_character(x, y);
 	if (hsnum < 0)
 		return nullptr;
-	return &game.chars[hsnum];
+	return &_GP(game).chars[hsnum];
 }
 
 extern int char_lowest_yp, obj_lowest_yp;
 
 int is_pos_on_character(int xx, int yy) {
 	int cc, sppic, lowestyp = 0, lowestwas = -1;
-	for (cc = 0; cc < game.numcharacters; cc++) {
-		if (game.chars[cc].room != displayed_room) continue;
-		if (game.chars[cc].on == 0) continue;
-		if (game.chars[cc].flags & CHF_NOINTERACT) continue;
-		if (game.chars[cc].view < 0) continue;
-		CharacterInfo *chin = &game.chars[cc];
+	for (cc = 0; cc < _GP(game).numcharacters; cc++) {
+		if (_GP(game).chars[cc].room != displayed_room) continue;
+		if (_GP(game).chars[cc].on == 0) continue;
+		if (_GP(game).chars[cc].flags & CHF_NOINTERACT) continue;
+		if (_GP(game).chars[cc].view < 0) continue;
+		CharacterInfo *chin = &_GP(game).chars[cc];
 
 		if ((chin->view < 0) ||
 		        (chin->loop >= views[chin->view].numLoops) ||
@@ -2159,8 +2156,8 @@ int is_pos_on_character(int xx, int yy) {
 		sppic = views[chin->view].loops[chin->loop].frames[chin->frame].pic;
 		int usewid = charextra[cc].width;
 		int usehit = charextra[cc].height;
-		if (usewid == 0) usewid = game.SpriteInfos[sppic].Width;
-		if (usehit == 0) usehit = game.SpriteInfos[sppic].Height;
+		if (usewid == 0) usewid = _GP(game).SpriteInfos[sppic].Width;
+		if (usehit == 0) usehit = _GP(game).SpriteInfos[sppic].Height;
 		int xxx = chin->x - game_to_data_coord(usewid) / 2;
 		int yyy = chin->get_effective_y() - game_to_data_coord(usehit);
 
@@ -2182,7 +2179,7 @@ int is_pos_on_character(int xx, int yy) {
 }
 
 void get_char_blocking_rect(int charid, int *x1, int *y1, int *width, int *y2) {
-	CharacterInfo *char1 = &game.chars[charid];
+	CharacterInfo *char1 = &_GP(game).chars[charid];
 	int cwidth, fromx;
 
 	if (char1->blocking_width < 1)
@@ -2224,11 +2221,11 @@ int is_char_on_another(int sourceChar, int ww, int *fromxptr, int *cwidptr) {
 	// this char somehow, allow them through
 	if ((sourceChar >= 0) &&
 	        // x/width are left and width co-ords, so they need >= and <
-	        (game.chars[sourceChar].x >= fromx) &&
-	        (game.chars[sourceChar].x < fromx + cwidth) &&
+	        (_GP(game).chars[sourceChar].x >= fromx) &&
+	        (_GP(game).chars[sourceChar].x < fromx + cwidth) &&
 	        // y1/y2 are the top/bottom co-ords, so they need >= / <=
-	        (game.chars[sourceChar].y >= y1) &&
-	        (game.chars[sourceChar].y <= y2))
+	        (_GP(game).chars[sourceChar].y >= y1) &&
+	        (_GP(game).chars[sourceChar].y <= y2))
 		return 1;
 
 	return 0;
@@ -2280,11 +2277,11 @@ void _DisplayThoughtCore(int chid, const char *displbuf) {
 
 	int xpp = -1, ypp = -1, width = -1;
 
-	if ((game.options[OPT_SPEECHTYPE] == 0) || (game.chars[chid].thinkview <= 0)) {
+	if ((_GP(game).options[OPT_SPEECHTYPE] == 0) || (_GP(game).chars[chid].thinkview <= 0)) {
 		// lucasarts-style, so we want a speech bubble actually above
 		// their head (or if they have no think anim in Sierra-style)
 		width = data_to_game_coord(play.speech_bubble_width);
-		xpp = play.RoomToScreenX(data_to_game_coord(game.chars[chid].x)) - width / 2;
+		xpp = play.RoomToScreenX(data_to_game_coord(_GP(game).chars[chid].x)) - width / 2;
 		if (xpp < 0)
 			xpp = 0;
 		// -1 will automatically put it above the char's head
@@ -2298,8 +2295,8 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	if (!is_valid_character(aschar))
 		quit("!DisplaySpeech: invalid character");
 
-	CharacterInfo *speakingChar = &game.chars[aschar];
-	if ((speakingChar->view < 0) || (speakingChar->view >= game.numviews))
+	CharacterInfo *speakingChar = &_GP(game).chars[aschar];
+	if ((speakingChar->view < 0) || (speakingChar->view >= _GP(game).numviews))
 		quit("!DisplaySpeech: character has invalid view");
 
 	if (is_text_overlay > 0) {
@@ -2373,7 +2370,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 		}
 	}
 
-	if (useview >= game.numviews)
+	if (useview >= _GP(game).numviews)
 		quitprintf("!Character.Say: attempted to use view %d for animation, but it does not exist", useview + 1);
 
 	int tdxp = xx, tdyp = yy;
@@ -2388,11 +2385,11 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	// find out if this may be refactored and voice started only in one place.
 	try_auto_play_speech(texx, texx, aschar, true);
 
-	if (game.options[OPT_SPEECHTYPE] == 3)
+	if (_GP(game).options[OPT_SPEECHTYPE] == 3)
 		remove_screen_overlay(OVER_COMPLETE);
 	our_eip = 1500;
 
-	if (game.options[OPT_SPEECHTYPE] == 0)
+	if (_GP(game).options[OPT_SPEECHTYPE] == 0)
 		allowShrink = 1;
 
 	if (speakingChar->idleleft < 0)  {
@@ -2408,7 +2405,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 		viewWasLocked = 1;
 
 	/*if ((speakingChar->room == displayed_room) ||
-	((useview >= 0) && (game.options[OPT_SPEECHTYPE] > 0)) ) {*/
+	((useview >= 0) && (_GP(game).options[OPT_SPEECHTYPE] > 0)) ) {*/
 
 	if (speakingChar->room == displayed_room) {
 		// If the character is in this room, go for it - otherwise
@@ -2448,8 +2445,8 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 
 		if (tdyp < 0) {
 			int sppic = views[speakingChar->view].loops[speakingChar->loop].frames[0].pic;
-			int height = (charextra[aschar].height < 1) ? game.SpriteInfos[sppic].Height : charextra[aschar].height;
-			tdyp = view->RoomToScreen(0, data_to_game_coord(game.chars[aschar].get_effective_y()) - height).first.Y
+			int height = (charextra[aschar].height < 1) ? _GP(game).SpriteInfos[sppic].Height : charextra[aschar].height;
+			tdyp = view->RoomToScreen(0, data_to_game_coord(_GP(game).chars[aschar].get_effective_y()) - height).first.Y
 			       - get_fixed_pixel_size(5);
 			if (isThought) // if it's a thought, lift it a bit further up
 				tdyp -= get_fixed_pixel_size(10);
@@ -2459,15 +2456,15 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 
 		our_eip = 152;
 
-		if ((useview >= 0) && (game.options[OPT_SPEECHTYPE] > 0)) {
+		if ((useview >= 0) && (_GP(game).options[OPT_SPEECHTYPE] > 0)) {
 			// Sierra-style close-up portrait
 
 			if (play.swap_portrait_lastchar != aschar) {
 				// if the portraits are set to Alternate, OR they are
 				// set to Left but swap_portrait has been set to 1 (the old
 				// method for enabling it), then swap them round
-				if ((game.options[OPT_PORTRAITSIDE] == PORTRAIT_ALTERNATE) ||
-				        ((game.options[OPT_PORTRAITSIDE] == 0) &&
+				if ((_GP(game).options[OPT_PORTRAITSIDE] == PORTRAIT_ALTERNATE) ||
+				        ((_GP(game).options[OPT_PORTRAITSIDE] == 0) &&
 				         (play.swap_portrait_side > 0))) {
 
 					if (play.swap_portrait_side == 2)
@@ -2476,19 +2473,19 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 						play.swap_portrait_side = 2;
 				}
 
-				if (game.options[OPT_PORTRAITSIDE] == PORTRAIT_XPOSITION) {
+				if (_GP(game).options[OPT_PORTRAITSIDE] == PORTRAIT_XPOSITION) {
 					// Portrait side based on character X-positions
 					if (play.swap_portrait_lastchar < 0) {
 						// No previous character been spoken to
 						// therefore, assume it's the player
-						if (game.playercharacter != aschar && game.chars[game.playercharacter].room == speakingChar->room && game.chars[game.playercharacter].on == 1)
-							play.swap_portrait_lastchar = game.playercharacter;
+						if (_GP(game).playercharacter != aschar && _GP(game).chars[_GP(game).playercharacter].room == speakingChar->room && _GP(game).chars[_GP(game).playercharacter].on == 1)
+							play.swap_portrait_lastchar = _GP(game).playercharacter;
 						else
 							// The player's not here. Find another character in this room
 							// that it could be
-							for (int ce = 0; ce < game.numcharacters; ce++) {
-								if ((game.chars[ce].room == speakingChar->room) &&
-								        (game.chars[ce].on == 1) &&
+							for (int ce = 0; ce < _GP(game).numcharacters; ce++) {
+								if ((_GP(game).chars[ce].room == speakingChar->room) &&
+								        (_GP(game).chars[ce].on == 1) &&
 								        (ce != aschar)) {
 									play.swap_portrait_lastchar = ce;
 									break;
@@ -2499,7 +2496,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 					if (play.swap_portrait_lastchar >= 0) {
 						// if this character is right of the one before, put the
 						// portrait on the right
-						if (speakingChar->x > game.chars[play.swap_portrait_lastchar].x)
+						if (speakingChar->x > _GP(game).chars[play.swap_portrait_lastchar].x)
 							play.swap_portrait_side = -1;
 						else
 							play.swap_portrait_side = 0;
@@ -2510,8 +2507,8 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			} else
 				// If the portrait side is based on the character's X position and the same character is
 				// speaking, compare against the previous *previous* character to see where the speech should be
-				if (game.options[OPT_PORTRAITSIDE] == PORTRAIT_XPOSITION && play.swap_portrait_lastlastchar >= 0) {
-					if (speakingChar->x > game.chars[play.swap_portrait_lastlastchar].x)
+				if (_GP(game).options[OPT_PORTRAITSIDE] == PORTRAIT_XPOSITION && play.swap_portrait_lastlastchar >= 0) {
+					if (speakingChar->x > _GP(game).chars[play.swap_portrait_lastlastchar].x)
 						play.swap_portrait_side = -1;
 					else
 						play.swap_portrait_side = 0;
@@ -2520,26 +2517,26 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			// Determine whether to display the portrait on the left or right
 			int portrait_on_right = 0;
 
-			if (game.options[OPT_SPEECHTYPE] == 3) {
+			if (_GP(game).options[OPT_SPEECHTYPE] == 3) {
 			}  // always on left with QFG-style speech
 			else if ((play.swap_portrait_side == 1) ||
 			         (play.swap_portrait_side == -1) ||
-			         (game.options[OPT_PORTRAITSIDE] == PORTRAIT_RIGHT))
+			         (_GP(game).options[OPT_PORTRAITSIDE] == PORTRAIT_RIGHT))
 				portrait_on_right = 1;
 
 
 			int bigx = 0, bigy = 0, kk;
 			ViewStruct *viptr = &views[useview];
 			for (kk = 0; kk < viptr->loops[0].numFrames; kk++) {
-				int tw = game.SpriteInfos[viptr->loops[0].frames[kk].pic].Width;
+				int tw = _GP(game).SpriteInfos[viptr->loops[0].frames[kk].pic].Width;
 				if (tw > bigx) bigx = tw;
-				tw = game.SpriteInfos[viptr->loops[0].frames[kk].pic].Height;
+				tw = _GP(game).SpriteInfos[viptr->loops[0].frames[kk].pic].Height;
 				if (tw > bigy) bigy = tw;
 			}
 
 			// if they accidentally used a large full-screen image as the sierra-style
 			// talk view, correct it
-			if ((game.options[OPT_SPEECHTYPE] != 3) && (bigx > ui_view.GetWidth() - get_fixed_pixel_size(50)))
+			if ((_GP(game).options[OPT_SPEECHTYPE] != 3) && (bigx > ui_view.GetWidth() - get_fixed_pixel_size(50)))
 				bigx = ui_view.GetWidth() - get_fixed_pixel_size(50);
 
 			if (widd > 0)
@@ -2552,9 +2549,9 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			facetalk_qfg4_override_placement_x = false;
 			facetalk_qfg4_override_placement_y = false;
 
-			if (game.options[OPT_SPEECHTYPE] == 3) {
+			if (_GP(game).options[OPT_SPEECHTYPE] == 3) {
 				// QFG4-style whole screen picture
-				closeupface = BitmapHelper::CreateBitmap(ui_view.GetWidth(), ui_view.GetHeight(), spriteset[viptr->loops[0].frames[0].pic]->GetColorDepth());
+				closeupface = BitmapHelper::CreateBitmap(ui_view.GetWidth(), ui_view.GetHeight(), _GP(spriteset)[viptr->loops[0].frames[0].pic]->GetColorDepth());
 				closeupface->Clear(0);
 				if (xx < 0 && play.speech_portrait_placement) {
 					facetalk_qfg4_override_placement_x = true;
@@ -2564,7 +2561,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 					facetalk_qfg4_override_placement_y = true;
 					view_frame_y = play.speech_portrait_y;
 				} else {
-					view_frame_y = ui_view.GetHeight() / 2 - game.SpriteInfos[viptr->loops[0].frames[0].pic].Height / 2;
+					view_frame_y = ui_view.GetHeight() / 2 - _GP(game).SpriteInfos[viptr->loops[0].frames[0].pic].Height / 2;
 				}
 				bigx = ui_view.GetWidth() / 2 - get_fixed_pixel_size(20);
 				ovr_type = OVER_COMPLETE;
@@ -2579,14 +2576,14 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 				else
 					ovr_yp = yy;
 
-				closeupface = BitmapHelper::CreateTransparentBitmap(bigx + 1, bigy + 1, spriteset[viptr->loops[0].frames[0].pic]->GetColorDepth());
+				closeupface = BitmapHelper::CreateTransparentBitmap(bigx + 1, bigy + 1, _GP(spriteset)[viptr->loops[0].frames[0].pic]->GetColorDepth());
 				ovr_type = OVER_PICTURE;
 
 				if (yy < 0)
 					tdyp = ovr_yp + get_textwindow_top_border_height(play.speech_textwindow_gui);
 			}
 			const ViewFrame *vf = &viptr->loops[0].frames[0];
-			const bool closeupface_has_alpha = (game.SpriteInfos[vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
+			const bool closeupface_has_alpha = (_GP(game).SpriteInfos[vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
 			DrawViewFrame(closeupface, vf, view_frame_x, view_frame_y);
 
 			int overlay_x = get_fixed_pixel_size(10);
@@ -2632,7 +2629,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 				tdxp += get_textwindow_border_width(play.speech_textwindow_gui) / 2;
 				allowShrink = 2;
 			}
-			if (game.options[OPT_SPEECHTYPE] == 3)
+			if (_GP(game).options[OPT_SPEECHTYPE] == 3)
 				overlay_x = 0;
 			face_talking = add_screen_overlay(overlay_x, ovr_yp, ovr_type, closeupface, closeupface_has_alpha);
 			facetalkframe = 0;
@@ -2644,7 +2641,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			facetalkAllowBlink = 1;
 			if ((isThought) && (speakingChar->flags & CHF_NOBLINKANDTHINK))
 				facetalkAllowBlink = 0;
-			facetalkchar = &game.chars[aschar];
+			facetalkchar = &_GP(game).chars[aschar];
 			if (facetalkchar->blinktimer < 0)
 				facetalkchar->blinktimer = facetalkchar->blinkinterval;
 			textcol = -textcol;
@@ -2712,7 +2709,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	our_eip = 155;
 	_display_at(tdxp, tdyp, bwidth, texx, DISPLAYTEXT_SPEECH, textcol, isThought, allowShrink, overlayPositionFixed);
 	our_eip = 156;
-	if ((play.in_conversation > 0) && (game.options[OPT_SPEECHTYPE] == 3))
+	if ((play.in_conversation > 0) && (_GP(game).options[OPT_SPEECHTYPE] == 3))
 		closeupface = nullptr;
 	if (closeupface != nullptr)
 		remove_screen_overlay(ovr_type);
@@ -2764,9 +2761,9 @@ int GetLipSyncFrame(const char *curtex, int *stroffs) {
 	"Y/H/K/Q/C", "I/T/E/X/th", "U/W", "S/Z/J/ch", NULL,
 	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};*/
 
-	int bestfit_len = 0, bestfit = game.default_lipsync_frame;
+	int bestfit_len = 0, bestfit = _GP(game).default_lipsync_frame;
 	for (int aa = 0; aa < MAXLIPSYNCFRAMES; aa++) {
-		char *tptr = game.lipSyncFrameLetters[aa];
+		char *tptr = _GP(game).lipSyncFrameLetters[aa];
 		while (tptr[0] != 0) {
 			int lenthisbit = strlen(tptr);
 			if (strchr(tptr, '/'))
@@ -2817,7 +2814,7 @@ int update_lip_sync(int talkview, int talkloop, int *talkframeptr) {
 Rect GetCharacterRoomBBox(int charid, bool use_frame_0) {
 	int width, height;
 	const CharacterExtras &chex = charextra[charid];
-	const CharacterInfo &chin = game.chars[charid];
+	const CharacterInfo &chin = _GP(game).chars[charid];
 	int frame = use_frame_0 ? 0 : chin.frame;
 	int pic = views[chin.view].loops[chin.loop].frames[frame].pic;
 	scale_sprite_size(pic, chex.zoom, &width, &height);
diff --git a/engines/ags/engine/ac/characterinfo_engine.cpp b/engines/ags/engine/ac/characterinfo_engine.cpp
index 9264f21b38..457de9e35c 100644
--- a/engines/ags/engine/ac/characterinfo_engine.cpp
+++ b/engines/ags/engine/ac/characterinfo_engine.cpp
@@ -34,6 +34,7 @@
 #include "ags/engine/main/maindefines_ex.h"    // RETURN_CONTINUE
 #include "ags/engine/main/update.h"
 #include "ags/engine/media/audio/audio_system.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -41,7 +42,7 @@ namespace AGS3 {
 using namespace AGS::Shared;
 
 extern ViewStruct *views;
-extern GameSetupStruct game;
+
 extern int displayed_room;
 extern GameState play;
 extern int char_speaking;
@@ -108,13 +109,13 @@ void CharacterInfo::UpdateMoveAndAnim(int &char_index, CharacterExtras *chex, in
 }
 
 void CharacterInfo::UpdateFollowingExactlyCharacter() {
-	x = game.chars[following].x;
-	y = game.chars[following].y;
-	z = game.chars[following].z;
-	room = game.chars[following].room;
-	prevroom = game.chars[following].prevroom;
+	x = _GP(game).chars[following].x;
+	y = _GP(game).chars[following].y;
+	z = _GP(game).chars[following].z;
+	room = _GP(game).chars[following].room;
+	prevroom = _GP(game).chars[following].prevroom;
 
-	int usebase = game.chars[following].get_baseline();
+	int usebase = _GP(game).chars[following].get_baseline();
 
 	if (flags & CHF_BEHINDSHEPHERD)
 		baseline = usebase - 1;
@@ -267,7 +268,7 @@ int CharacterInfo::update_character_animating(int &aa, int &doing_nothing) {
 			doing_nothing = 1;
 
 		if (wait > 0) wait--;
-		else if ((char_speaking == aa) && (game.options[OPT_LIPSYNCTEXT] != 0)) {
+		else if ((char_speaking == aa) && (_GP(game).options[OPT_LIPSYNCTEXT] != 0)) {
 			// currently talking with lip-sync speech
 			int fraa = frame;
 			wait = update_lip_sync(view, loop, &fraa) - 1;
@@ -379,12 +380,12 @@ void CharacterInfo::update_character_follower(int &aa, int &numSheep, int *follo
 	else if ((following >= 0) && (doing_nothing == 1)) {
 		short distaway = (followinfo >> 8) & 0x00ff;
 		// no character in this room
-		if ((game.chars[following].on == 0) || (on == 0));
+		if ((_GP(game).chars[following].on == 0) || (on == 0));
 		else if (room < 0) {
 			room++;
 			if (room == 0) {
 				// appear in the new room
-				room = game.chars[following].room;
+				room = _GP(game).chars[following].room;
 				x = play.entered_at_x;
 				y = play.entered_at_y;
 			}
@@ -392,12 +393,12 @@ void CharacterInfo::update_character_follower(int &aa, int &numSheep, int *follo
 		// wait a bit, so we're not constantly walking
 		else if (Random(100) < (followinfo & 0x00ff));
 		// the followed character has changed room
-		else if ((room != game.chars[following].room)
-			&& (game.chars[following].on == 0))
+		else if ((room != _GP(game).chars[following].room)
+			&& (_GP(game).chars[following].on == 0))
 			;  // do nothing if the player isn't visible
-		else if (room != game.chars[following].room) {
+		else if (room != _GP(game).chars[following].room) {
 			prevroom = room;
-			room = game.chars[following].room;
+			room = _GP(game).chars[following].room;
 
 			if (room == displayed_room) {
 				// only move to the room-entered position if coming into
@@ -427,16 +428,16 @@ void CharacterInfo::update_character_follower(int &aa, int &numSheep, int *follo
 		} else if (room != displayed_room) {
 			// if the characetr is following another character and
 			// neither is in the current room, don't try to move
-		} else if ((abs(game.chars[following].x - x) > distaway + 30) |
-			(abs(game.chars[following].y - y) > distaway + 30) |
+		} else if ((abs(_GP(game).chars[following].x - x) > distaway + 30) |
+			(abs(_GP(game).chars[following].y - y) > distaway + 30) |
 			((followinfo & 0x00ff) == 0)) {
 			// in same room
 			int goxoffs = (Random(50) - 25);
 			// make sure he's not standing on top of the other man
 			if (goxoffs < 0) goxoffs -= distaway;
 			else goxoffs += distaway;
-			walk_character(aa, game.chars[following].x + goxoffs,
-				game.chars[following].y + (Random(50) - 25), 0, true);
+			walk_character(aa, _GP(game).chars[following].x + goxoffs,
+				_GP(game).chars[following].y + (Random(50) - 25), 0, true);
 			doing_nothing = 0;
 		}
 	}
diff --git a/engines/ags/engine/ac/dialog.cpp b/engines/ags/engine/ac/dialog.cpp
index aa7fd563c5..de5d419f4e 100644
--- a/engines/ags/engine/ac/dialog.cpp
+++ b/engines/ags/engine/ac/dialog.cpp
@@ -63,19 +63,19 @@
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 extern ccInstance *dialogScriptsInst;
 extern int in_new_room;
 extern CharacterInfo *playerchar;
-extern SpriteCache spriteset;
+
 extern AGSPlatformDriver *platform;
 extern int cur_mode, cur_cursor;
 extern IGraphicsDriver *gfxDriver;
@@ -109,7 +109,7 @@ int Dialog_DisplayOptions(ScriptDialog *sd, int sayChosenOption) {
 	if ((sayChosenOption < 1) || (sayChosenOption > 3))
 		quit("!Dialog.DisplayOptions: invalid parameter passed");
 
-	int chose = show_dialog_options(sd->id, sayChosenOption, (game.options[OPT_RUNGAMEDLGOPTS] != 0));
+	int chose = show_dialog_options(sd->id, sayChosenOption, (_GP(game).options[OPT_RUNGAMEDLGOPTS] != 0));
 	if (chose != CHOSE_TEXTPARSER) {
 		chose++;
 	}
@@ -215,7 +215,7 @@ int run_dialog_script(DialogTopic *dtpp, int dialogID, int offse, int optionInde
 				get_dialog_script_parameters(script, &param1, &param2);
 
 				if (param1 == DCHAR_PLAYER)
-					param1 = game.playercharacter;
+					param1 = _GP(game).playercharacter;
 
 				if (param1 == DCHAR_NARRATOR)
 					Display(get_translation(old_speech_lines[param2]));
@@ -355,14 +355,14 @@ int write_dialog_options(Bitmap *ds, bool ds_has_alpha, int dlgxp, int curyp, in
 
 		break_up_text_into_lines(get_translation(dtop->optionnames[(int)disporder[ww]]), Lines, areawid - (2 * padding + 2 + bullet_wid), usingfont);
 		dispyp[ww] = curyp;
-		if (game.dialog_bullet > 0) {
-			draw_gui_sprite_v330(ds, game.dialog_bullet, dlgxp, curyp, ds_has_alpha);
+		if (_GP(game).dialog_bullet > 0) {
+			draw_gui_sprite_v330(ds, _GP(game).dialog_bullet, dlgxp, curyp, ds_has_alpha);
 		}
-		if (game.options[OPT_DIALOGNUMBERED] == kDlgOptNumbering) {
+		if (_GP(game).options[OPT_DIALOGNUMBERED] == kDlgOptNumbering) {
 			char tempbfr[20];
 			int actualpicwid = 0;
-			if (game.dialog_bullet > 0)
-				actualpicwid = game.SpriteInfos[game.dialog_bullet].Width + 3;
+			if (_GP(game).dialog_bullet > 0)
+				actualpicwid = _GP(game).SpriteInfos[_GP(game).dialog_bullet].Width + 3;
 
 			sprintf(tempbfr, "%d.", ww + 1);
 			wouttext_outline(ds, dlgxp + actualpicwid, curyp, usingfont, text_color, tempbfr);
@@ -372,7 +372,7 @@ int write_dialog_options(Bitmap *ds, bool ds_has_alpha, int dlgxp, int curyp, in
 			curyp += linespacing;
 		}
 		if (ww < numdisp - 1)
-			curyp += data_to_game_coord(game.options[OPT_DIALOGGAP]);
+			curyp += data_to_game_coord(_GP(game).options[OPT_DIALOGGAP]);
 	}
 	return curyp;
 }
@@ -383,9 +383,9 @@ int write_dialog_options(Bitmap *ds, bool ds_has_alpha, int dlgxp, int curyp, in
 		needheight = 0;\
 		for (int i = 0; i < numdisp; ++i) {\
 			break_up_text_into_lines(get_translation(dtop->optionnames[(int)disporder[i]]), Lines, areawid-(2*padding+2+bullet_wid), usingfont);\
-			needheight += getheightoflines(usingfont, Lines.Count()) + data_to_game_coord(game.options[OPT_DIALOGGAP]);\
+			needheight += getheightoflines(usingfont, Lines.Count()) + data_to_game_coord(_GP(game).options[OPT_DIALOGGAP]);\
 		}\
-		if (parserInput) needheight += parserInput->Height + data_to_game_coord(game.options[OPT_DIALOGGAP]);\
+		if (parserInput) needheight += parserInput->Height + data_to_game_coord(_GP(game).options[OPT_DIALOGGAP]);\
 	}
 
 
@@ -395,7 +395,7 @@ void draw_gui_for_dialog_options(Bitmap *ds, GUIMain *guib, int dlgxp, int dlgyp
 		ds->FillRect(Rect(dlgxp, dlgyp, dlgxp + guib->Width, dlgyp + guib->Height), draw_color);
 	}
 	if (guib->BgImage > 0)
-		GfxUtil::DrawSpriteWithTransparency(ds, spriteset[guib->BgImage], dlgxp, dlgyp);
+		GfxUtil::DrawSpriteWithTransparency(ds, _GP(spriteset)[guib->BgImage], dlgxp, dlgyp);
 }
 
 bool get_custom_dialog_options_dimensions(int dlgnum) {
@@ -482,7 +482,7 @@ void DialogOptions::Prepare(int _dlgnum, bool _runGameLoopsInBackground) {
 	parserInput = nullptr;
 	dtop = nullptr;
 
-	if ((dlgnum < 0) || (dlgnum >= game.numdialog))
+	if ((dlgnum < 0) || (dlgnum >= _GP(game).numdialog))
 		quit("!RunDialog: invalid dialog number specified");
 
 	can_run_delayed_command();
@@ -491,11 +491,11 @@ void DialogOptions::Prepare(int _dlgnum, bool _runGameLoopsInBackground) {
 
 	update_polled_stuff_if_runtime();
 
-	if (game.dialog_bullet > 0)
-		bullet_wid = game.SpriteInfos[game.dialog_bullet].Width + 3;
+	if (_GP(game).dialog_bullet > 0)
+		bullet_wid = _GP(game).SpriteInfos[_GP(game).dialog_bullet].Width + 3;
 
 	// numbered options, leave space for the numbers
-	if (game.options[OPT_DIALOGNUMBERED] == kDlgOptNumbering)
+	if (_GP(game).options[OPT_DIALOGNUMBERED] == kDlgOptNumbering)
 		bullet_wid += wgettextwidth_compensate("9. ", usingfont);
 
 	said_text = 0;
@@ -503,7 +503,7 @@ void DialogOptions::Prepare(int _dlgnum, bool _runGameLoopsInBackground) {
 	update_polled_stuff_if_runtime();
 
 	const Rect &ui_view = play.GetUIViewport();
-	tempScrn = BitmapHelper::CreateBitmap(ui_view.GetWidth(), ui_view.GetHeight(), game.GetColorDepth());
+	tempScrn = BitmapHelper::CreateBitmap(ui_view.GetWidth(), ui_view.GetHeight(), _GP(game).GetColorDepth());
 
 	set_mouse_cursor(CURS_ARROW);
 
@@ -559,8 +559,8 @@ void DialogOptions::Show() {
 		dirtywidth = data_to_game_coord(ccDialogOptionsRendering.width);
 		dirtyheight = data_to_game_coord(ccDialogOptionsRendering.height);
 		dialog_abs_x = dirtyx;
-	} else if (game.options[OPT_DIALOGIFACE] > 0) {
-		GUIMain *guib = &guis[game.options[OPT_DIALOGIFACE]];
+	} else if (_GP(game).options[OPT_DIALOGIFACE] > 0) {
+		GUIMain *guib = &guis[_GP(game).options[OPT_DIALOGIFACE]];
 		if (guib->IsTextWindow()) {
 			// text-window, so do the QFG4-style speech options
 			is_textwindow = 1;
@@ -580,7 +580,7 @@ void DialogOptions::Show() {
 
 			GET_OPTIONS_HEIGHT
 
-			if (game.options[OPT_DIALOGUPWARDS]) {
+			if (_GP(game).options[OPT_DIALOGUPWARDS]) {
 				// They want the options upwards from the bottom
 				dlgyp = (guib->Y + guib->Height) - needheight;
 			}
@@ -625,7 +625,7 @@ void DialogOptions::Redraw() {
 	wantRefresh = true;
 
 	if (usingCustomRendering) {
-		tempScrn = recycle_bitmap(tempScrn, game.GetColorDepth(),
+		tempScrn = recycle_bitmap(tempScrn, _GP(game).GetColorDepth(),
 		                          data_to_game_coord(ccDialogOptionsRendering.width),
 		                          data_to_game_coord(ccDialogOptionsRendering.height));
 	}
@@ -664,7 +664,7 @@ void DialogOptions::Redraw() {
 		// text window behind the options
 		areawid = data_to_game_coord(play.max_dialogoption_width);
 		int biggest = 0;
-		padding = guis[game.options[OPT_DIALOGIFACE]].Padding;
+		padding = guis[_GP(game).options[OPT_DIALOGIFACE]].Padding;
 		for (int i = 0; i < numdisp; ++i) {
 			break_up_text_into_lines(get_translation(dtop->optionnames[(int)disporder[i]]), Lines, areawid - ((2 * padding + 2) + bullet_wid), usingfont);
 			if (longestline > biggest)
@@ -676,7 +676,7 @@ void DialogOptions::Redraw() {
 		if (areawid < data_to_game_coord(play.min_dialogoption_width)) {
 			areawid = data_to_game_coord(play.min_dialogoption_width);
 			if (play.min_dialogoption_width > play.max_dialogoption_width)
-				quit("!game.min_dialogoption_width is larger than game.max_dialogoption_width");
+				quit("!_GP(game).min_dialogoption_width is larger than _GP(game).max_dialogoption_width");
 		}
 
 		GET_OPTIONS_HEIGHT
@@ -685,13 +685,13 @@ void DialogOptions::Redraw() {
 		int txoffs = 0, tyoffs = 0, yspos = ui_view.GetHeight() / 2 - (2 * padding + needheight) / 2;
 		int xspos = ui_view.GetWidth() / 2 - areawid / 2;
 		// shift window to the right if QG4-style full-screen pic
-		if ((game.options[OPT_SPEECHTYPE] == 3) && (said_text > 0))
+		if ((_GP(game).options[OPT_SPEECHTYPE] == 3) && (said_text > 0))
 			xspos = (ui_view.GetWidth() - areawid) - get_fixed_pixel_size(10);
 
 		// needs to draw the right text window, not the default
 		Bitmap *text_window_ds = nullptr;
-		draw_text_window(&text_window_ds, false, &txoffs, &tyoffs, &xspos, &yspos, &areawid, nullptr, needheight, game.options[OPT_DIALOGIFACE]);
-		options_surface_has_alpha = guis[game.options[OPT_DIALOGIFACE]].HasAlphaChannel();
+		draw_text_window(&text_window_ds, false, &txoffs, &tyoffs, &xspos, &yspos, &areawid, nullptr, needheight, _GP(game).options[OPT_DIALOGIFACE]);
+		options_surface_has_alpha = guis[_GP(game).options[OPT_DIALOGIFACE]].HasAlphaChannel();
 		// since draw_text_window incrases the width, restore it
 		areawid = savedwid;
 
@@ -718,11 +718,11 @@ void DialogOptions::Redraw() {
 		if (wantRefresh) {
 			// redraw the black background so that anti-alias
 			// fonts don't re-alias themselves
-			if (game.options[OPT_DIALOGIFACE] == 0) {
+			if (_GP(game).options[OPT_DIALOGIFACE] == 0) {
 				color_t draw_color = ds->GetCompatibleColor(16);
 				ds->FillRect(Rect(0, dlgyp - 1, ui_view.GetWidth() - 1, ui_view.GetHeight() - 1), draw_color);
 			} else {
-				GUIMain *guib = &guis[game.options[OPT_DIALOGIFACE]];
+				GUIMain *guib = &guis[_GP(game).options[OPT_DIALOGIFACE]];
 				if (!guib->IsTextWindow())
 					draw_gui_for_dialog_options(ds, guib, dlgxp, dlgyp);
 			}
@@ -731,10 +731,10 @@ void DialogOptions::Redraw() {
 		dirtyx = 0;
 		dirtywidth = ui_view.GetWidth();
 
-		if (game.options[OPT_DIALOGIFACE] > 0) {
+		if (_GP(game).options[OPT_DIALOGIFACE] > 0) {
 			// the whole GUI area should be marked dirty in order
 			// to ensure it gets drawn
-			GUIMain *guib = &guis[game.options[OPT_DIALOGIFACE]];
+			GUIMain *guib = &guis[_GP(game).options[OPT_DIALOGIFACE]];
 			dirtyheight = guib->Height;
 			dirtyy = dlgyp;
 			options_surface_has_alpha = guib->HasAlphaChannel();
@@ -767,14 +767,14 @@ void DialogOptions::Redraw() {
 
 	if (parserInput) {
 		// Set up the text box, if present
-		parserInput->Y = curyp + data_to_game_coord(game.options[OPT_DIALOGGAP]);
+		parserInput->Y = curyp + data_to_game_coord(_GP(game).options[OPT_DIALOGGAP]);
 		parserInput->Width = areawid - get_fixed_pixel_size(10);
 		parserInput->TextColor = playerchar->talkcolor;
 		if (mouseison == DLG_OPTION_PARSER)
 			parserInput->TextColor = forecol;
 
-		if (game.dialog_bullet) { // the parser X will get moved in a second
-			draw_gui_sprite_v330(ds, game.dialog_bullet, parserInput->X, parserInput->Y, options_surface_has_alpha);
+		if (_GP(game).dialog_bullet) { // the parser X will get moved in a second
+			draw_gui_sprite_v330(ds, _GP(game).dialog_bullet, parserInput->X, parserInput->Y, options_surface_has_alpha);
 		}
 
 		parserInput->Width -= bullet_wid;
@@ -818,7 +818,7 @@ void DialogOptions::Redraw() {
 }
 
 bool DialogOptions::Run() {
-	const bool new_custom_render = usingCustomRendering && game.options[OPT_DIALOGOPTIONSAPI] >= 0;
+	const bool new_custom_render = usingCustomRendering && _GP(game).options[OPT_DIALOGOPTIONSAPI] >= 0;
 
 	if (runGameLoopsInBackground) {
 		play.disabled_user_interface++;
@@ -861,7 +861,7 @@ bool DialogOptions::Run() {
 			run_function_on_non_blocking_thread(&runDialogOptionKeyPressHandlerFunc);
 		}
 		// Allow selection of options by keyboard shortcuts
-		else if (game.options[OPT_DIALOGNUMBERED] >= kDlgOptKeysOnly &&
+		else if (_GP(game).options[OPT_DIALOGNUMBERED] >= kDlgOptKeysOnly &&
 		         gkey >= '1' && gkey <= '9') {
 			gkey -= '1';
 			if (gkey < numdisp) {
@@ -1044,7 +1044,7 @@ int show_dialog_options(int _dlgnum, int sayChosenOption, bool _runGameLoopsInBa
 		}
 
 		if (sayTheOption)
-			DisplaySpeech(get_translation(option_name), game.playercharacter);
+			DisplaySpeech(get_translation(option_name), _GP(game).playercharacter);
 	}
 
 	return dialog_choice;
@@ -1074,7 +1074,7 @@ void do_conversation(int dlgnum) {
 		dlgnum = tocar;
 
 	while (dlgnum >= 0) {
-		if (dlgnum >= game.numdialog)
+		if (dlgnum >= _GP(game).numdialog)
 			quit("!RunDialog: invalid dialog number specified");
 
 		dtop = &dialog[dlgnum];
@@ -1106,7 +1106,7 @@ void do_conversation(int dlgnum) {
 			}
 		}
 
-		int chose = show_dialog_options(dlgnum, SAYCHOSEN_USEFLAG, (game.options[OPT_RUNGAMEDLGOPTS] != 0));
+		int chose = show_dialog_options(dlgnum, SAYCHOSEN_USEFLAG, (_GP(game).options[OPT_RUNGAMEDLGOPTS] != 0));
 		if (SHOULD_QUIT)
 			return;
 
diff --git a/engines/ags/engine/ac/display.cpp b/engines/ags/engine/ac/display.cpp
index 9726ad63e3..1a4d7c5c17 100644
--- a/engines/ags/engine/ac/display.cpp
+++ b/engines/ags/engine/ac/display.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-//include <math.h>
-
 #include "ags/engine/ac/display.h"
 #include "ags/shared/ac/common.h"
 #include "ags/shared/font/agsfontrenderer.h"
@@ -54,6 +52,7 @@
 #include "ags/engine/ac/mouse.h"
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/ac/timer.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -62,11 +61,11 @@ using namespace AGS::Shared;
 using namespace AGS::Shared::BitmapHelper;
 
 extern GameState play;
-extern GameSetupStruct game;
+
 extern int longestline;
 extern AGSPlatformDriver *platform;
 extern int loops_per_character;
-extern SpriteCache spriteset;
+
 
 int display_message_aschar = 0;
 
@@ -82,8 +81,8 @@ struct DisplayVars {
 // allowShrink = 0 for none, 1 for leftwards, 2 for rightwards
 // pass blocking=2 to create permanent overlay
 int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int usingfont, int asspch, int isThought, int allowShrink, bool overlayPositionFixed) {
-	const bool use_speech_textwindow = (asspch < 0) && (game.options[OPT_SPEECHTYPE] >= 2);
-	const bool use_thought_gui = (isThought) && (game.options[OPT_THOUGHTGUI] > 0);
+	const bool use_speech_textwindow = (asspch < 0) && (_GP(game).options[OPT_SPEECHTYPE] >= 2);
+	const bool use_thought_gui = (isThought) && (_GP(game).options[OPT_THOUGHTGUI] > 0);
 
 	bool alphaChannel = false;
 	char todis[STD_BUFFER_SIZE];
@@ -92,7 +91,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 	if (use_speech_textwindow)
 		usingGui = play.speech_textwindow_gui;
 	else if (use_thought_gui)
-		usingGui = game.options[OPT_THOUGHTGUI];
+		usingGui = _GP(game).options[OPT_THOUGHTGUI];
 
 	int padding = get_textwindow_padding(usingGui);
 	int paddingScaled = get_fixed_pixel_size(padding);
@@ -176,7 +175,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 	if (disp_type < DISPLAYTEXT_NORMALOVERLAY)
 		remove_screen_overlay(OVER_TEXTMSG); // remove any previous blocking texts
 
-	Bitmap *text_window_ds = BitmapHelper::CreateTransparentBitmap((wii > 0) ? wii : 2, disp.fulltxtheight + extraHeight, game.GetColorDepth());
+	Bitmap *text_window_ds = BitmapHelper::CreateTransparentBitmap((wii > 0) ? wii : 2, disp.fulltxtheight + extraHeight, _GP(game).GetColorDepth());
 
 	// inform draw_text_window to free the old bitmap
 	const bool wantFreeScreenop = true;
@@ -208,7 +207,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 			if (usingGui > 0) {
 				alphaChannel = guis[usingGui].HasAlphaChannel();
 			}
-		} else if ((ShouldAntiAliasText()) && (game.GetColorDepth() >= 24))
+		} else if ((ShouldAntiAliasText()) && (_GP(game).GetColorDepth() >= 24))
 			alphaChannel = true;
 
 		for (size_t ee = 0; ee < Lines.Count(); ee++) {
@@ -218,7 +217,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 			// centre the text
 			if (asspch < 0) {
 				if ((usingGui >= 0) &&
-					((game.options[OPT_SPEECHTYPE] >= 2) || (isThought)))
+					((_GP(game).options[OPT_SPEECHTYPE] >= 2) || (isThought)))
 					text_color = text_window_ds->GetCompatibleColor(guis[usingGui].FgColor);
 				else
 					text_color = text_window_ds->GetCompatibleColor(-asspch);
@@ -233,8 +232,8 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 		int xoffs, yoffs, oriwid = wii - padding * 2;
 		draw_text_window_and_bar(&text_window_ds, wantFreeScreenop, &xoffs, &yoffs, &xx, &yy, &wii, &text_color);
 
-		if (game.options[OPT_TWCUSTOM] > 0) {
-			alphaChannel = guis[game.options[OPT_TWCUSTOM]].HasAlphaChannel();
+		if (_GP(game).options[OPT_TWCUSTOM] > 0) {
+			alphaChannel = guis[_GP(game).options[OPT_TWCUSTOM]].HasAlphaChannel();
 		}
 
 		adjust_y_coordinate_for_text(&yoffs, usingfont);
@@ -422,7 +421,7 @@ int GetTextDisplayTime(const char *text, int canberel) {
 		return 0;
 
 	if (play.text_speed + play.text_speed_modifier <= 0)
-		quit("!Text speed is zero; unable to display text. Check your game.text_speed settings.");
+		quit("!Text speed is zero; unable to display text. Check your _GP(game).text_speed settings.");
 
 	// Store how many game loops per character of text
 	// This is calculated using a hard-coded 15 for the text speed,
@@ -438,7 +437,7 @@ int GetTextDisplayTime(const char *text, int canberel) {
 }
 
 bool ShouldAntiAliasText() {
-	return (game.options[OPT_ANTIALIASFONTS] != 0);
+	return (_GP(game).options[OPT_ANTIALIASFONTS] != 0);
 }
 
 #if defined (AGS_FONTOUTLINE_MOREOPAQUE)
@@ -468,14 +467,14 @@ void wouttextxy_AutoOutline_Semitransparent2Opaque(Bitmap *map) {
 
 // Draw outline that is calculated from the text font, not derived from an outline font
 void wouttextxy_AutoOutline(Bitmap *ds, size_t font, int32_t color, const char *texx, int &xxp, int &yyp) {
-	int const thickness = game.fonts.at(font).AutoOutlineThickness;
-	auto const style = game.fonts.at(font).AutoOutlineStyle;
+	int const thickness = _GP(game).fonts.at(font).AutoOutlineThickness;
+	auto const style = _GP(game).fonts.at(font).AutoOutlineStyle;
 	if (thickness <= 0)
 		return;
 
 	// 16-bit games should use 32-bit stencils to keep anti-aliasing working
 	int const  ds_cd = ds->GetColorDepth();
-	bool const antialias = ds_cd >= 16 && game.options[OPT_ANTIALIASFONTS] != 0 && !is_bitmap_font(font);
+	bool const antialias = ds_cd >= 16 && _GP(game).options[OPT_ANTIALIASFONTS] != 0 && !is_bitmap_font(font);
 	int const  stencil_cd = antialias ? 32 : ds_cd;
 	if (antialias) // This is to make sure TTFs render proper alpha channel in 16-bit games too
 		color |= makeacol32(0, 0, 0, 0xff);
@@ -592,12 +591,12 @@ int wgettextwidth_compensate(const char *tex, int font) {
 
 void do_corner(Bitmap *ds, int sprn, int x, int y, int offx, int offy) {
 	if (sprn < 0) return;
-	if (spriteset[sprn] == nullptr) {
+	if (_GP(spriteset)[sprn] == nullptr) {
 		sprn = 0;
 	}
 
-	x = x + offx * game.SpriteInfos[sprn].Width;
-	y = y + offy * game.SpriteInfos[sprn].Height;
+	x = x + offx * _GP(game).SpriteInfos[sprn].Width;
+	y = y + offy * _GP(game).SpriteInfos[sprn].Height;
 	draw_gui_sprite_v330(ds, sprn, x, y);
 }
 
@@ -631,13 +630,13 @@ void draw_button_background(Bitmap *ds, int xx1, int yy1, int xx2, int yy2, GUIM
 		if (iep->BgColor > 0)
 			ds->FillRect(Rect(xx1, yy1, xx2, yy2), draw_color);
 
-		int leftRightWidth = game.SpriteInfos[get_but_pic(iep, 4)].Width;
-		int topBottomHeight = game.SpriteInfos[get_but_pic(iep, 6)].Height;
+		int leftRightWidth = _GP(game).SpriteInfos[get_but_pic(iep, 4)].Width;
+		int topBottomHeight = _GP(game).SpriteInfos[get_but_pic(iep, 6)].Height;
 		if (iep->BgImage > 0) {
 			if ((loaded_game_file_version <= kGameVersion_272) // 2.xx
-				&& (spriteset[iep->BgImage]->GetWidth() == 1)
-				&& (spriteset[iep->BgImage]->GetHeight() == 1)
-				&& (*((const unsigned int *)spriteset[iep->BgImage]->GetData()) == 0x00FF00FF)) {
+				&& (_GP(spriteset)[iep->BgImage]->GetWidth() == 1)
+				&& (_GP(spriteset)[iep->BgImage]->GetHeight() == 1)
+				&& (*((const unsigned int *)_GP(spriteset)[iep->BgImage]->GetData()) == 0x00FF00FF)) {
 				// Don't draw fully transparent dummy GUI backgrounds
 			} else {
 				// offset the background image and clip it so that it is drawn
@@ -653,20 +652,20 @@ void draw_button_background(Bitmap *ds, int xx1, int yy1, int xx2, int yy2, GUIM
 					bgoffsy = bgoffsyStart;
 					while (bgoffsy <= bgfinishy) {
 						draw_gui_sprite_v330(ds, iep->BgImage, bgoffsx, bgoffsy);
-						bgoffsy += game.SpriteInfos[iep->BgImage].Height;
+						bgoffsy += _GP(game).SpriteInfos[iep->BgImage].Height;
 					}
-					bgoffsx += game.SpriteInfos[iep->BgImage].Width;
+					bgoffsx += _GP(game).SpriteInfos[iep->BgImage].Width;
 				}
 				// return to normal clipping rectangle
 				ds->SetClip(Rect(0, 0, ds->GetWidth() - 1, ds->GetHeight() - 1));
 			}
 		}
 		int uu;
-		for (uu = yy1; uu <= yy2; uu += game.SpriteInfos[get_but_pic(iep, 4)].Height) {
+		for (uu = yy1; uu <= yy2; uu += _GP(game).SpriteInfos[get_but_pic(iep, 4)].Height) {
 			do_corner(ds, get_but_pic(iep, 4), xx1, uu, -1, 0); // left side
 			do_corner(ds, get_but_pic(iep, 5), xx2 + 1, uu, 0, 0); // right side
 		}
-		for (uu = xx1; uu <= xx2; uu += game.SpriteInfos[get_but_pic(iep, 6)].Width) {
+		for (uu = xx1; uu <= xx2; uu += _GP(game).SpriteInfos[get_but_pic(iep, 6)].Width) {
 			do_corner(ds, get_but_pic(iep, 6), uu, yy1, 0, -1); // top side
 			do_corner(ds, get_but_pic(iep, 7), uu, yy2 + 1, 0, 0); // bottom side
 		}
@@ -686,8 +685,8 @@ int get_textwindow_border_width(int twgui) {
 	if (!guis[twgui].IsTextWindow())
 		quit("!GUI set as text window but is not actually a text window GUI");
 
-	int borwid = game.SpriteInfos[get_but_pic(&guis[twgui], 4)].Width +
-		game.SpriteInfos[get_but_pic(&guis[twgui], 5)].Width;
+	int borwid = _GP(game).SpriteInfos[get_but_pic(&guis[twgui], 4)].Width +
+		_GP(game).SpriteInfos[get_but_pic(&guis[twgui], 5)].Width;
 
 	return borwid;
 }
@@ -700,7 +699,7 @@ int get_textwindow_top_border_height(int twgui) {
 	if (!guis[twgui].IsTextWindow())
 		quit("!GUI set as text window but is not actually a text window GUI");
 
-	return game.SpriteInfos[get_but_pic(&guis[twgui], 6)].Height;
+	return _GP(game).SpriteInfos[get_but_pic(&guis[twgui], 6)].Height;
 }
 
 // Get the padding for a text window
@@ -709,8 +708,8 @@ int get_textwindow_padding(int ifnum) {
 	int result;
 
 	if (ifnum < 0)
-		ifnum = game.options[OPT_TWCUSTOM];
-	if (ifnum > 0 && ifnum < game.numgui)
+		ifnum = _GP(game).options[OPT_TWCUSTOM];
+	if (ifnum > 0 && ifnum < _GP(game).numgui)
 		result = guis[ifnum].Padding;
 	else
 		result = TEXTWINDOW_PADDING_DEFAULT;
@@ -723,7 +722,7 @@ void draw_text_window(Bitmap **text_window_ds, bool should_free_ds,
 
 	Bitmap *ds = *text_window_ds;
 	if (ifnum < 0)
-		ifnum = game.options[OPT_TWCUSTOM];
+		ifnum = _GP(game).options[OPT_TWCUSTOM];
 
 	if (ifnum <= 0) {
 		if (ovrheight)
@@ -734,25 +733,25 @@ void draw_text_window(Bitmap **text_window_ds, bool should_free_ds,
 		xins[0] = 3;
 		yins[0] = 3;
 	} else {
-		if (ifnum >= game.numgui)
-			quitprintf("!Invalid GUI %d specified as text window (total GUIs: %d)", ifnum, game.numgui);
+		if (ifnum >= _GP(game).numgui)
+			quitprintf("!Invalid GUI %d specified as text window (total GUIs: %d)", ifnum, _GP(game).numgui);
 		if (!guis[ifnum].IsTextWindow())
 			quit("!GUI set as text window but is not actually a text window GUI");
 
 		int tbnum = get_but_pic(&guis[ifnum], 0);
 
 		wii[0] += get_textwindow_border_width(ifnum);
-		xx[0] -= game.SpriteInfos[tbnum].Width;
-		yy[0] -= game.SpriteInfos[tbnum].Height;
+		xx[0] -= _GP(game).SpriteInfos[tbnum].Width;
+		yy[0] -= _GP(game).SpriteInfos[tbnum].Height;
 		if (ovrheight == 0)
 			ovrheight = disp.fulltxtheight;
 
 		if (should_free_ds)
 			delete *text_window_ds;
 		int padding = get_textwindow_padding(ifnum);
-		*text_window_ds = BitmapHelper::CreateTransparentBitmap(wii[0], ovrheight + (padding * 2) + game.SpriteInfos[tbnum].Height * 2, game.GetColorDepth());
+		*text_window_ds = BitmapHelper::CreateTransparentBitmap(wii[0], ovrheight + (padding * 2) + _GP(game).SpriteInfos[tbnum].Height * 2, _GP(game).GetColorDepth());
 		ds = *text_window_ds;
-		int xoffs = game.SpriteInfos[tbnum].Width, yoffs = game.SpriteInfos[tbnum].Height;
+		int xoffs = _GP(game).SpriteInfos[tbnum].Width, yoffs = _GP(game).SpriteInfos[tbnum].Height;
 		draw_button_background(ds, xoffs, yoffs, (ds->GetWidth() - xoffs) - 1, (ds->GetHeight() - yoffs) - 1, &guis[ifnum]);
 		if (set_text_color)
 			*set_text_color = ds->GetCompatibleColor(guis[ifnum].FgColor);
@@ -770,7 +769,7 @@ void draw_text_window_and_bar(Bitmap **text_window_ds, bool should_free_ds,
 		// top bar on the dialog window with character's name
 		// create an enlarged window, then free the old one
 		Bitmap *ds = *text_window_ds;
-		Bitmap *newScreenop = BitmapHelper::CreateBitmap(ds->GetWidth(), ds->GetHeight() + topBar.height, game.GetColorDepth());
+		Bitmap *newScreenop = BitmapHelper::CreateBitmap(ds->GetWidth(), ds->GetHeight() + topBar.height, _GP(game).GetColorDepth());
 		newScreenop->Blit(ds, 0, 0, 0, topBar.height, ds->GetWidth(), ds->GetHeight());
 		delete *text_window_ds;
 		*text_window_ds = newScreenop;
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index d304e37cfe..ffe0071305 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -70,7 +70,7 @@
 #include "ags/engine/gfx/blender.h"
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/ac/game.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -89,7 +89,7 @@ extern "C" void ios_render();
 #endif
 
 extern GameSetup usetup;
-extern GameSetupStruct game;
+
 extern GameState play;
 extern int convert_16bit_bgr;
 extern ScriptSystem scsystem;
@@ -105,7 +105,7 @@ extern IDriverDependantBitmap *walkBehindBitmap[MAX_WALK_BEHINDS];
 extern int walkBehindsCachedForBgNum;
 extern WalkBehindMethodEnum walkBehindMethod;
 extern int walk_behind_baselines_changed;
-extern SpriteCache spriteset;
+
 extern RoomStatus *croom;
 extern int our_eip;
 extern int in_new_room;
@@ -256,7 +256,7 @@ Bitmap *convert_32_to_32bgr(Bitmap *tempbl) {
 Bitmap *AdjustBitmapForUseWithDisplayMode(Bitmap *bitmap, bool has_alpha) {
 	const int bmp_col_depth = bitmap->GetColorDepth();
 	//const int sys_col_depth = System_GetColorDepth();
-	const int game_col_depth = game.GetColorDepth();
+	const int game_col_depth = _GP(game).GetColorDepth();
 	Bitmap *new_bitmap = bitmap;
 
 	//
@@ -308,7 +308,7 @@ Bitmap *ReplaceBitmapWithSupportedFormat(Bitmap *bitmap) {
 }
 
 Bitmap *PrepareSpriteForUse(Bitmap *bitmap, bool has_alpha) {
-	bool must_switch_palette = bitmap->GetColorDepth() == 8 && game.GetColorDepth() > 8;
+	bool must_switch_palette = bitmap->GetColorDepth() == 8 && _GP(game).GetColorDepth() > 8;
 	if (must_switch_palette)
 		select_palette(palette);
 
@@ -336,7 +336,7 @@ PBitmap PrepareSpriteForUse(PBitmap bitmap, bool has_alpha) {
 }
 
 Bitmap *CopyScreenIntoBitmap(int width, int height, bool at_native_res) {
-	Bitmap *dst = new Bitmap(width, height, game.GetColorDepth());
+	Bitmap *dst = new Bitmap(width, height, _GP(game).GetColorDepth());
 	GraphicResolution want_fmt;
 	// If the size and color depth are supported we may copy right into our bitmap
 	if (gfxDriver->GetCopyOfScreenIntoBitmap(dst, at_native_res, &want_fmt))
@@ -365,80 +365,80 @@ Bitmap *CopyScreenIntoBitmap(int width, int height, bool at_native_res) {
 // Multiplies up the number of pixels depending on the current
 // resolution, to give a relatively fixed size at any game res
 AGS_INLINE int get_fixed_pixel_size(int pixels) {
-	return pixels * game.GetRelativeUIMult();
+	return pixels * _GP(game).GetRelativeUIMult();
 }
 
 AGS_INLINE int data_to_game_coord(int coord) {
-	return coord * game.GetDataUpscaleMult();
+	return coord * _GP(game).GetDataUpscaleMult();
 }
 
 AGS_INLINE void data_to_game_coords(int *x, int *y) {
-	const int mul = game.GetDataUpscaleMult();
+	const int mul = _GP(game).GetDataUpscaleMult();
 	x[0] *= mul;
 	y[0] *= mul;
 }
 
 AGS_INLINE void data_to_game_round_up(int *x, int *y) {
-	const int mul = game.GetDataUpscaleMult();
+	const int mul = _GP(game).GetDataUpscaleMult();
 	x[0] = x[0] * mul + (mul - 1);
 	y[0] = y[0] * mul + (mul - 1);
 }
 
 AGS_INLINE int game_to_data_coord(int coord) {
-	return coord / game.GetDataUpscaleMult();
+	return coord / _GP(game).GetDataUpscaleMult();
 }
 
 AGS_INLINE void game_to_data_coords(int &x, int &y) {
-	const int mul = game.GetDataUpscaleMult();
+	const int mul = _GP(game).GetDataUpscaleMult();
 	x /= mul;
 	y /= mul;
 }
 
 AGS_INLINE int game_to_data_round_up(int coord) {
-	const int mul = game.GetDataUpscaleMult();
+	const int mul = _GP(game).GetDataUpscaleMult();
 	return (coord / mul) + (mul - 1);
 }
 
 AGS_INLINE void ctx_data_to_game_coord(int &x, int &y, bool hires_ctx) {
-	if (hires_ctx && !game.IsLegacyHiRes()) {
+	if (hires_ctx && !_GP(game).IsLegacyHiRes()) {
 		x /= HIRES_COORD_MULTIPLIER;
 		y /= HIRES_COORD_MULTIPLIER;
-	} else if (!hires_ctx && game.IsLegacyHiRes()) {
+	} else if (!hires_ctx && _GP(game).IsLegacyHiRes()) {
 		x *= HIRES_COORD_MULTIPLIER;
 		y *= HIRES_COORD_MULTIPLIER;
 	}
 }
 
 AGS_INLINE void ctx_data_to_game_size(int &w, int &h, bool hires_ctx) {
-	if (hires_ctx && !game.IsLegacyHiRes()) {
+	if (hires_ctx && !_GP(game).IsLegacyHiRes()) {
 		w = Math::Max(1, (w / HIRES_COORD_MULTIPLIER));
 		h = Math::Max(1, (h / HIRES_COORD_MULTIPLIER));
-	} else if (!hires_ctx && game.IsLegacyHiRes()) {
+	} else if (!hires_ctx && _GP(game).IsLegacyHiRes()) {
 		w *= HIRES_COORD_MULTIPLIER;
 		h *= HIRES_COORD_MULTIPLIER;
 	}
 }
 
 AGS_INLINE int ctx_data_to_game_size(int size, bool hires_ctx) {
-	if (hires_ctx && !game.IsLegacyHiRes())
+	if (hires_ctx && !_GP(game).IsLegacyHiRes())
 		return Math::Max(1, (size / HIRES_COORD_MULTIPLIER));
-	if (!hires_ctx && game.IsLegacyHiRes())
+	if (!hires_ctx && _GP(game).IsLegacyHiRes())
 		return size * HIRES_COORD_MULTIPLIER;
 	return size;
 }
 
 AGS_INLINE int game_to_ctx_data_size(int size, bool hires_ctx) {
-	if (hires_ctx && !game.IsLegacyHiRes())
+	if (hires_ctx && !_GP(game).IsLegacyHiRes())
 		return size * HIRES_COORD_MULTIPLIER;
-	else if (!hires_ctx && game.IsLegacyHiRes())
+	else if (!hires_ctx && _GP(game).IsLegacyHiRes())
 		return Math::Max(1, (size / HIRES_COORD_MULTIPLIER));
 	return size;
 }
 
 AGS_INLINE void defgame_to_finalgame_coords(int &x, int &y) {
 	// Note we support only upscale now
-	x *= game.GetScreenUpscaleMult();
-	y *= game.GetScreenUpscaleMult();
+	x *= _GP(game).GetScreenUpscaleMult();
+	y *= _GP(game).GetScreenUpscaleMult();
 }
 
 // End resolution system functions
@@ -470,14 +470,14 @@ void destroy_blank_image() {
 
 int MakeColor(int color_index) {
 	color_t real_color = 0;
-	__my_setcolor(&real_color, color_index, game.GetColorDepth());
+	__my_setcolor(&real_color, color_index, _GP(game).GetColorDepth());
 	return real_color;
 }
 
 void init_draw_method() {
 	if (gfxDriver->HasAcceleratedTransform()) {
 		walkBehindMethod = DrawAsSeparateSprite;
-		create_blank_image(game.GetColorDepth());
+		create_blank_image(_GP(game).GetColorDepth());
 	} else {
 		walkBehindMethod = DrawOverCharSprite;
 	}
@@ -502,7 +502,7 @@ void dispose_room_drawdata() {
 void on_mainviewport_changed() {
 	if (!gfxDriver->RequiresFullRedrawEachFrame()) {
 		init_invalid_regions(-1, play.GetMainViewport().GetSize(), RectWH(play.GetMainViewport().GetSize()));
-		if (game.GetGameRes().ExceedsByAny(play.GetMainViewport().GetSize()))
+		if (_GP(game).GetGameRes().ExceedsByAny(play.GetMainViewport().GetSize()))
 			clear_letterbox_borders();
 	}
 }
@@ -671,11 +671,11 @@ void render_black_borders() {
 	if (gfxDriver->UsesMemoryBackBuffer())
 		return;
 	{
-		gfxDriver->BeginSpriteBatch(RectWH(game.GetGameRes()), SpriteTransform());
+		gfxDriver->BeginSpriteBatch(RectWH(_GP(game).GetGameRes()), SpriteTransform());
 		const Rect &viewport = play.GetMainViewport();
 		if (viewport.Top > 0) {
 			// letterbox borders
-			blankImage->SetStretch(game.GetGameRes().Width, viewport.Top, false);
+			blankImage->SetStretch(_GP(game).GetGameRes().Width, viewport.Top, false);
 			gfxDriver->DrawSprite(0, 0, blankImage);
 			gfxDriver->DrawSprite(0, viewport.Bottom + 1, blankImage);
 		}
@@ -711,10 +711,10 @@ void render_to_screen() {
 			gfxDriver->Render(0, play.shake_screen_yoff, (GlobalFlipType)play.screen_flipped);
 
 #if AGS_PLATFORM_OS_ANDROID
-			if (game.color_depth == 1)
+			if (_GP(game).color_depth == 1)
 				android_render();
 #elif AGS_PLATFORM_OS_IOS
-			if (game.color_depth == 1)
+			if (_GP(game).color_depth == 1)
 				ios_render();
 #endif
 
@@ -728,8 +728,8 @@ void render_to_screen() {
 // Blanks out borders around main viewport in case it became smaller (e.g. after loading another room)
 void clear_letterbox_borders() {
 	const Rect &viewport = play.GetMainViewport();
-	gfxDriver->ClearRectangle(0, 0, game.GetGameRes().Width - 1, viewport.Top - 1, nullptr);
-	gfxDriver->ClearRectangle(0, viewport.Bottom + 1, game.GetGameRes().Width - 1, game.GetGameRes().Height - 1, nullptr);
+	gfxDriver->ClearRectangle(0, 0, _GP(game).GetGameRes().Width - 1, viewport.Top - 1, nullptr);
+	gfxDriver->ClearRectangle(0, viewport.Bottom + 1, _GP(game).GetGameRes().Width - 1, _GP(game).GetGameRes().Height - 1, nullptr);
 }
 
 void draw_game_screen_callback() {
@@ -756,7 +756,7 @@ void draw_sprite_support_alpha(Bitmap *ds, bool ds_has_alpha, int xpos, int ypos
 	if (alpha <= 0)
 		return;
 
-	if (game.options[OPT_SPRITEALPHA] == kSpriteAlphaRender_Proper) {
+	if (_GP(game).options[OPT_SPRITEALPHA] == kSpriteAlphaRender_Proper) {
 		GfxUtil::DrawSpriteBlend(ds, Point(xpos, ypos), image, blend_mode, ds_has_alpha, src_has_alpha, alpha);
 	}
 	// Backwards-compatible drawing
@@ -770,7 +770,7 @@ void draw_sprite_support_alpha(Bitmap *ds, bool ds_has_alpha, int xpos, int ypos
 
 void draw_sprite_slot_support_alpha(Bitmap *ds, bool ds_has_alpha, int xpos, int ypos, int src_slot,
                                     BlendMode blend_mode, int alpha) {
-	draw_sprite_support_alpha(ds, ds_has_alpha, xpos, ypos, spriteset[src_slot], (game.SpriteInfos[src_slot].Flags & SPF_ALPHACHANNEL) != 0,
+	draw_sprite_support_alpha(ds, ds_has_alpha, xpos, ypos, _GP(spriteset)[src_slot], (_GP(game).SpriteInfos[src_slot].Flags & SPF_ALPHACHANNEL) != 0,
 	                          blend_mode, alpha);
 }
 
@@ -961,7 +961,7 @@ void add_to_sprite_list(IDriverDependantBitmap *spp, int xx, int yy, int baselin
 		return;
 
 	SpriteListEntry sprite;
-	if ((sprNum >= 0) && ((game.SpriteInfos[sprNum].Flags & SPF_ALPHACHANNEL) != 0))
+	if ((sprNum >= 0) && ((_GP(game).SpriteInfos[sprNum].Flags & SPF_ALPHACHANNEL) != 0))
 		sprite.hasAlphaChannel = true;
 	else
 		sprite.hasAlphaChannel = false;
@@ -997,15 +997,15 @@ void repair_alpha_channel(Bitmap *dest, Bitmap *bgpic) {
 
 // used by GUI renderer to draw images
 void draw_gui_sprite(Bitmap *ds, int pic, int x, int y, bool use_alpha, BlendMode blend_mode) {
-	Bitmap *sprite = spriteset[pic];
+	Bitmap *sprite = _GP(spriteset)[pic];
 	const bool ds_has_alpha  = ds->GetColorDepth() == 32;
-	const bool src_has_alpha = (game.SpriteInfos[pic].Flags & SPF_ALPHACHANNEL) != 0;
+	const bool src_has_alpha = (_GP(game).SpriteInfos[pic].Flags & SPF_ALPHACHANNEL) != 0;
 
-	if (use_alpha && game.options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper) {
+	if (use_alpha && _GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper) {
 		GfxUtil::DrawSpriteBlend(ds, Point(x, y), sprite, blend_mode, ds_has_alpha, src_has_alpha);
 	}
 	// Backwards-compatible drawing
-	else if (use_alpha && ds_has_alpha && game.options[OPT_NEWGUIALPHA] == kGuiAlphaRender_AdditiveAlpha) {
+	else if (use_alpha && ds_has_alpha && _GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_AdditiveAlpha) {
 		if (src_has_alpha)
 			set_additive_alpha_blender();
 		else
@@ -1119,7 +1119,7 @@ void get_local_tint(int xpp, int ypp, int nolight,
 		}
 
 		int tint_sat = (tint_level >> 24) & 0xFF;
-		if ((game.color_depth == 1) || ((tint_level & 0x00ffffff) == 0) ||
+		if ((_GP(game).color_depth == 1) || ((tint_level & 0x00ffffff) == 0) ||
 		        (tint_sat == 0))
 			tint_level = 0;
 
@@ -1169,13 +1169,13 @@ void apply_tint_or_light(int actspsindex, int light_level,
 
 // In a 256-colour game, we cannot do tinting or lightening
 // (but we can do darkening, if light_level < 0)
-	if (game.color_depth == 1) {
+	if (_GP(game).color_depth == 1) {
 		if ((light_level > 0) || (tint_amount != 0))
 			return;
 	}
 
 // we can only do tint/light if the colour depths match
-	if (game.GetColorDepth() == actsps[actspsindex]->GetColorDepth()) {
+	if (_GP(game).GetColorDepth() == actsps[actspsindex]->GetColorDepth()) {
 		Bitmap *oldwas;
 		// if the caller supplied a source bitmap, ->Blit from it
 		// (used as a speed optimisation where possible)
@@ -1199,7 +1199,7 @@ void apply_tint_or_light(int actspsindex, int light_level,
 			int lit_amnt;
 			active_spr->FillTransparent();
 			// It's a light level, not a tint
-			if (game.color_depth == 1) {
+			if (_GP(game).color_depth == 1) {
 				// 256-col
 				lit_amnt = (250 - ((-light_level) * 5) / 2);
 			} else {
@@ -1254,37 +1254,37 @@ int scale_and_flip_sprite(int useindx, int coldept, int zoom_level,
 		if (isMirrored) {
 			Bitmap *tempspr = BitmapHelper::CreateBitmap(newwidth, newheight, coldept);
 			tempspr->Fill(actsps[useindx]->GetMaskColor());
-			if ((IS_ANTIALIAS_SPRITES) && ((game.SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) == 0))
-				tempspr->AAStretchBlt(spriteset[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
+			if ((IS_ANTIALIAS_SPRITES) && ((_GP(game).SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) == 0))
+				tempspr->AAStretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
 			else
-				tempspr->StretchBlt(spriteset[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
+				tempspr->StretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
 			active_spr->FlipBlt(tempspr, 0, 0, Shared::kBitmap_HFlip);
 			delete tempspr;
-		} else if ((IS_ANTIALIAS_SPRITES) && ((game.SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) == 0))
-			active_spr->AAStretchBlt(spriteset[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
+		} else if ((IS_ANTIALIAS_SPRITES) && ((_GP(game).SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) == 0))
+			active_spr->AAStretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
 		else
-			active_spr->StretchBlt(spriteset[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
+			active_spr->StretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
 
 		/*  AASTR2 version of code (doesn't work properly, gives black borders)
 		if (IS_ANTIALIAS_SPRITES) {
 		int aa_mode = AA_MASKED;
-		if (game.spriteflags[sppic] & SPF_ALPHACHANNEL)
+		if (_GP(game).spriteflags[sppic] & SPF_ALPHACHANNEL)
 		aa_mode |= AA_ALPHA | AA_RAW_ALPHA;
 		if (isMirrored)
 		aa_mode |= AA_HFLIP;
 
 		aa_set_mode(aa_mode);
-		->AAStretchBlt(actsps[useindx],spriteset[sppic],0,0,newwidth,newheight);
+		->AAStretchBlt(actsps[useindx],_GP(spriteset)[sppic],0,0,newwidth,newheight);
 		}
 		else if (isMirrored) {
 		Bitmap *tempspr = BitmapHelper::CreateBitmap_ (coldept, newwidth, newheight);
 		->Clear (tempspr, ->GetMaskColor(actsps[useindx]));
-		->StretchBlt (tempspr, spriteset[sppic], 0, 0, newwidth, newheight);
+		->StretchBlt (tempspr, _GP(spriteset)[sppic], 0, 0, newwidth, newheight);
 		->FlipBlt(Shared::kBitmap_HFlip, (actsps[useindx], tempspr, 0, 0);
 		wfreeblock (tempspr);
 		}
 		else
-		->StretchBlt(actsps[useindx],spriteset[sppic],0,0,newwidth,newheight);
+		->StretchBlt(actsps[useindx],_GP(spriteset)[sppic],0,0,newwidth,newheight);
 		*/
 		if (in_new_room)
 			unselect_palette();
@@ -1295,10 +1295,10 @@ int scale_and_flip_sprite(int useindx, int coldept, int zoom_level,
 		our_eip = 339;
 
 		if (isMirrored)
-			active_spr->FlipBlt(spriteset[sppic], 0, 0, Shared::kBitmap_HFlip);
+			active_spr->FlipBlt(_GP(spriteset)[sppic], 0, 0, Shared::kBitmap_HFlip);
 		else
 			actsps_used = 0;
-		//->Blit (spriteset[sppic], actsps[useindx], 0, 0, 0, 0, actsps[useindx]->GetWidth(), actsps[useindx]->GetHeight());
+		//->Blit (_GP(spriteset)[sppic], actsps[useindx], 0, 0, 0, 0, actsps[useindx]->GetWidth(), actsps[useindx]->GetHeight());
 	}
 
 	return actsps_used;
@@ -1313,12 +1313,12 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 	int useindx = aa;
 	bool hardwareAccelerated = !alwaysUseSoftware && gfxDriver->HasAcceleratedTransform();
 
-	if (spriteset[objs[aa].num] == nullptr)
+	if (_GP(spriteset)[objs[aa].num] == nullptr)
 		quitprintf("There was an error drawing object %d. Its current sprite, %d, is invalid.", aa, objs[aa].num);
 
-	int coldept = spriteset[objs[aa].num]->GetColorDepth();
-	int sprwidth = game.SpriteInfos[objs[aa].num].Width;
-	int sprheight = game.SpriteInfos[objs[aa].num].Height;
+	int coldept = _GP(spriteset)[objs[aa].num]->GetColorDepth();
+	int sprwidth = _GP(game).SpriteInfos[objs[aa].num].Width;
+	int sprheight = _GP(game).SpriteInfos[objs[aa].num].Height;
 
 	int tint_red, tint_green, tint_blue;
 	int tint_level, tint_light, light_level;
@@ -1440,13 +1440,13 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 		                                   objs[aa].num, sprwidth, sprheight, isMirrored);
 	} else {
 		// ensure actsps exists
-		actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, game.SpriteInfos[objs[aa].num].Width, game.SpriteInfos[objs[aa].num].Height);
+		actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, _GP(game).SpriteInfos[objs[aa].num].Width, _GP(game).SpriteInfos[objs[aa].num].Height);
 	}
 
 	// direct read from source bitmap, where possible
 	Bitmap *comeFrom = nullptr;
 	if (!actspsUsed)
-		comeFrom = spriteset[objs[aa].num];
+		comeFrom = _GP(spriteset)[objs[aa].num];
 
 	// apply tints or lightenings where appropriate, else just copy
 	// the source bitmap
@@ -1455,7 +1455,7 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 		                    tint_green, tint_blue, tint_light, coldept,
 		                    comeFrom);
 	} else if (!actspsUsed) {
-		actsps[useindx]->Blit(spriteset[objs[aa].num], 0, 0, 0, 0, game.SpriteInfos[objs[aa].num].Width, game.SpriteInfos[objs[aa].num].Height);
+		actsps[useindx]->Blit(_GP(spriteset)[objs[aa].num], 0, 0, 0, 0, _GP(game).SpriteInfos[objs[aa].num].Width, _GP(game).SpriteInfos[objs[aa].num].Height);
 	}
 
 	// Re-use the bitmap if it's the same size
@@ -1512,7 +1512,7 @@ void prepare_objects_for_drawing() {
 		}
 
 		if ((!actspsIntact) || (actspsbmp[useindx] == nullptr)) {
-			bool hasAlpha = (game.SpriteInfos[objs[aa].num].Flags & SPF_ALPHACHANNEL) != 0;
+			bool hasAlpha = (_GP(game).SpriteInfos[objs[aa].num].Flags & SPF_ALPHACHANNEL) != 0;
 
 			if (actspsbmp[useindx] != nullptr)
 				gfxDriver->DestroyDDB(actspsbmp[useindx]);
@@ -1597,13 +1597,13 @@ void prepare_characters_for_drawing() {
 	our_eip = 33;
 
 	// draw characters
-	for (int aa = 0; aa < game.numcharacters; aa++) {
-		if (game.chars[aa].on == 0) continue;
-		if (game.chars[aa].room != displayed_room) continue;
+	for (int aa = 0; aa < _GP(game).numcharacters; aa++) {
+		if (_GP(game).chars[aa].on == 0) continue;
+		if (_GP(game).chars[aa].room != displayed_room) continue;
 		eip_guinum = aa;
 		const int useindx = aa + MAX_ROOM_OBJECTS;
 
-		CharacterInfo *chin = &game.chars[aa];
+		CharacterInfo *chin = &_GP(game).chars[aa];
 		our_eip = 330;
 		// if it's on but set to view -1, they're being silly
 		if (chin->view < 0) {
@@ -1663,7 +1663,7 @@ void prepare_characters_for_drawing() {
 		int isMirrored = 0, specialpic = sppic;
 		bool usingCachedImage = false;
 
-		coldept = spriteset[sppic]->GetColorDepth();
+		coldept = _GP(spriteset)[sppic]->GetColorDepth();
 
 		// adjust the sppic if mirrored, so it doesn't accidentally
 		// cache the mirrored frame as the real one
@@ -1713,8 +1713,8 @@ void prepare_characters_for_drawing() {
 			// TODO: store width and height always, that's much simplier to use for reference!
 			charextra[aa].width = 0;
 			charextra[aa].height = 0;
-			newwidth = game.SpriteInfos[sppic].Width;
-			newheight = game.SpriteInfos[sppic].Height;
+			newwidth = _GP(game).SpriteInfos[sppic].Width;
+			newheight = _GP(game).SpriteInfos[sppic].Height;
 		}
 
 		our_eip = 3336;
@@ -1746,7 +1746,7 @@ void prepare_characters_for_drawing() {
 				                 newwidth, newheight, isMirrored);
 			} else {
 				// ensure actsps exists
-				actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, game.SpriteInfos[sppic].Width, game.SpriteInfos[sppic].Height);
+				actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, _GP(game).SpriteInfos[sppic].Width, _GP(game).SpriteInfos[sppic].Height);
 			}
 
 			our_eip = 335;
@@ -1757,14 +1757,14 @@ void prepare_characters_for_drawing() {
 				Bitmap *comeFrom = nullptr;
 				// if possible, direct read from the source image
 				if (!actspsUsed)
-					comeFrom = spriteset[sppic];
+					comeFrom = _GP(spriteset)[sppic];
 
 				apply_tint_or_light(useindx, light_level, tint_amount, tint_red,
 				                    tint_green, tint_blue, tint_light, coldept,
 				                    comeFrom);
 			} else if (!actspsUsed) {
 				// no scaling, flipping or tinting was done, so just blit it normally
-				actsps[useindx]->Blit(spriteset[sppic], 0, 0, 0, 0, actsps[useindx]->GetWidth(), actsps[useindx]->GetHeight());
+				actsps[useindx]->Blit(_GP(spriteset)[sppic], 0, 0, 0, 0, actsps[useindx]->GetWidth(), actsps[useindx]->GetHeight());
 			}
 
 			// update the character cache with the new image
@@ -1794,7 +1794,7 @@ void prepare_characters_for_drawing() {
 		}
 
 		if ((!usingCachedImage) || (actspsbmp[useindx] == nullptr)) {
-			bool hasAlpha = (game.SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) != 0;
+			bool hasAlpha = (_GP(game).SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) != 0;
 
 			actspsbmp[useindx] = recycle_ddb_bitmap(actspsbmp[useindx], actsps[useindx], hasAlpha);
 		}
@@ -1918,7 +1918,7 @@ void draw_fps(const Rect &viewport) {
 	static Bitmap *fpsDisplay = nullptr;
 	const int font = FONT_NORMAL;
 	if (fpsDisplay == nullptr) {
-		fpsDisplay = BitmapHelper::CreateBitmap(viewport.GetWidth(), (getfontheight_outlined(font) + get_fixed_pixel_size(5)), game.GetColorDepth());
+		fpsDisplay = BitmapHelper::CreateBitmap(viewport.GetWidth(), (getfontheight_outlined(font) + get_fixed_pixel_size(5)), _GP(game).GetColorDepth());
 		fpsDisplay = ReplaceBitmapWithSupportedFormat(fpsDisplay);
 	}
 	fpsDisplay->ClearTransparent();
@@ -1982,11 +1982,11 @@ void draw_gui_and_overlays() {
 			     "of an incorrect assignment in the game script.");
 		}
 		if (playerchar->activeinv < 1) gui_inv_pic = -1;
-		else gui_inv_pic = game.invinfo[playerchar->activeinv].pic;
+		else gui_inv_pic = _GP(game).invinfo[playerchar->activeinv].pic;
 		our_eip = 37;
 		if (guis_need_update) {
 			guis_need_update = 0;
-			for (aa = 0; aa < game.numgui; aa++) {
+			for (aa = 0; aa < _GP(game).numgui; aa++) {
 				if (!guis[aa].IsDisplayed()) continue;
 
 				if (guibg[aa] == nullptr)
@@ -2003,9 +2003,9 @@ void draw_gui_and_overlays() {
 				if (guis[aa].HasAlphaChannel()) {
 					isAlpha = true;
 
-					if ((game.options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Legacy) && (guis[aa].BgImage > 0)) {
+					if ((_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Legacy) && (guis[aa].BgImage > 0)) {
 						// old-style (pre-3.0.2) GUI alpha rendering
-						repair_alpha_channel(guibg[aa], spriteset[guis[aa].BgImage]);
+						repair_alpha_channel(guibg[aa], _GP(spriteset)[guis[aa].BgImage]);
 					}
 				}
 
@@ -2019,12 +2019,12 @@ void draw_gui_and_overlays() {
 		}
 		our_eip = 38;
 		// Draw the GUIs
-		for (int gg = 0; gg < game.numgui; gg++) {
+		for (int gg = 0; gg < _GP(game).numgui; gg++) {
 			aa = play.gui_draw_order[gg];
 			if (!guis[aa].IsDisplayed()) continue;
 
 			// Don't draw GUI if "GUIs Turn Off When Disabled"
-			if ((game.options[OPT_DISABLEOFF] == 3) &&
+			if ((_GP(game).options[OPT_DISABLEOFF] == 3) &&
 			        (all_buttons_disabled > 0) &&
 			        (guis[aa].PopupStyle != kGUIPopupNoAutoRemove))
 				continue;
@@ -2202,18 +2202,18 @@ void construct_game_screen_overlay(bool draw_mouse) {
 	// TODO: find out if it's okay to move cursor animation and state update
 	// to the update loop instead of doing it in the drawing routine
 	// update animating mouse cursor
-	if (game.mcurs[cur_cursor].view >= 0) {
+	if (_GP(game).mcurs[cur_cursor].view >= 0) {
 		ags_domouse(DOMOUSE_NOCURSOR);
 		// only on mousemove, and it's not moving
-		if (((game.mcurs[cur_cursor].flags & MCF_ANIMMOVE) != 0) &&
+		if (((_GP(game).mcurs[cur_cursor].flags & MCF_ANIMMOVE) != 0) &&
 		        (_G(mousex) == lastmx) && (_G(mousey) == lastmy));
 		// only on hotspot, and it's not on one
-		else if (((game.mcurs[cur_cursor].flags & MCF_HOTSPOT) != 0) &&
+		else if (((_GP(game).mcurs[cur_cursor].flags & MCF_HOTSPOT) != 0) &&
 		         (GetLocationType(game_to_data_coord(_G(mousex)), game_to_data_coord(_G(mousey))) == 0))
-			set_new_cursor_graphic(game.mcurs[cur_cursor].pic);
+			set_new_cursor_graphic(_GP(game).mcurs[cur_cursor].pic);
 		else if (mouse_delay > 0) mouse_delay--;
 		else {
-			int viewnum = game.mcurs[cur_cursor].view;
+			int viewnum = _GP(game).mcurs[cur_cursor].view;
 			int loopnum = 0;
 			if (loopnum >= views[viewnum].numLoops)
 				quitprintf("An animating mouse cursor is using view %d which has no loops", viewnum + 1);
@@ -2255,7 +2255,7 @@ void construct_game_screen_overlay(bool draw_mouse) {
 }
 
 void construct_engine_overlay() {
-	const Rect &viewport = RectWH(game.GetGameRes());
+	const Rect &viewport = RectWH(_GP(game).GetGameRes());
 	gfxDriver->BeginSpriteBatch(viewport, SpriteTransform());
 
 	// draw the debug console, if appropriate
@@ -2266,7 +2266,7 @@ void construct_engine_overlay() {
 		int barheight = getheightoflines(font, DEBUG_CONSOLE_NUMLINES - 1) + 4;
 
 		if (debugConsoleBuffer == nullptr) {
-			debugConsoleBuffer = BitmapHelper::CreateBitmap(viewport.GetWidth(), barheight, game.GetColorDepth());
+			debugConsoleBuffer = BitmapHelper::CreateBitmap(viewport.GetWidth(), barheight, _GP(game).GetColorDepth());
 			debugConsoleBuffer = ReplaceBitmapWithSupportedFormat(debugConsoleBuffer);
 		}
 
@@ -2307,7 +2307,7 @@ void render_graphics(IDriverDependantBitmap *extraBitmap, int extraX, int extraY
 		return;
 	// Don't render if we've just entered new room and are before fade-in
 	// TODO: find out why this is not skipped for 8-bit games
-	if ((in_new_room > 0) & (game.color_depth > 1))
+	if ((in_new_room > 0) & (_GP(game).color_depth > 1))
 		return;
 
 	// TODO: find out if it's okay to move shake to update function
diff --git a/engines/ags/engine/ac/drawingsurface.cpp b/engines/ags/engine/ac/drawingsurface.cpp
index 13b86da26a..3385d1a135 100644
--- a/engines/ags/engine/ac/drawingsurface.cpp
+++ b/engines/ags/engine/ac/drawingsurface.cpp
@@ -42,23 +42,23 @@
 #include "ags/engine/script/runtimescriptvalue.h"
 #include "ags/shared/gfx/gfx_def.h"
 #include "ags/engine/gfx/gfx_util.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 extern RoomStatus *croom;
 extern RoomObject *objs;
 extern CharacterCache *charcache;
 extern ObjectCache objcache[MAX_ROOM_OBJECTS];
-extern SpriteCache spriteset;
+
 extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
 
 // ** SCRIPT DRAWINGSURFACE OBJECT
@@ -91,11 +91,11 @@ void DrawingSurface_Release(ScriptDrawingSurface *sds) {
 						objcache[tt].sppic = -31999;
 				}
 			}
-			for (tt = 0; tt < game.numcharacters; tt++) {
+			for (tt = 0; tt < _GP(game).numcharacters; tt++) {
 				if (charcache[tt].sppic == sds->dynamicSpriteNumber)
 					charcache[tt].sppic = -31999;
 			}
-			for (tt = 0; tt < game.numgui; tt++) {
+			for (tt = 0; tt < _GP(game).numgui; tt++) {
 				if ((guis[tt].BgImage == sds->dynamicSpriteNumber) &&
 					(guis[tt].IsDisplayed())) {
 					guis_need_update = 1;
@@ -236,10 +236,10 @@ void DrawingSurface_DrawImageImpl(ScriptDrawingSurface *sds, Bitmap *src, int ds
 
 void DrawingSurface_DrawImageEx(ScriptDrawingSurface *sds, int dst_x, int dst_y, int slot, int trans, int dst_width, int dst_height,
 	int src_x, int src_y, int src_width, int src_height) {
-	if ((slot < 0) || (spriteset[slot] == nullptr))
+	if ((slot < 0) || (_GP(spriteset)[slot] == nullptr))
 		quit("!DrawingSurface.DrawImage: invalid sprite slot number specified");
-	DrawingSurface_DrawImageImpl(sds, spriteset[slot], dst_x, dst_y, trans, dst_width, dst_height,
-		src_x, src_y, src_width, src_height, slot, (game.SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
+	DrawingSurface_DrawImageImpl(sds, _GP(spriteset)[slot], dst_x, dst_y, trans, dst_width, dst_height,
+		src_x, src_y, src_width, src_height, slot, (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void DrawingSurface_DrawImage(ScriptDrawingSurface *sds, int xx, int yy, int slot, int trans, int width, int height) {
@@ -275,7 +275,7 @@ int DrawingSurface_GetDrawingColor(ScriptDrawingSurface *sds) {
 }
 
 void DrawingSurface_SetUseHighResCoordinates(ScriptDrawingSurface *sds, int highRes) {
-	if (game.AllowRelativeRes())
+	if (_GP(game).AllowRelativeRes())
 		sds->highResCoordinates = (highRes) ? 1 : 0;
 }
 
diff --git a/engines/ags/engine/ac/dynamicsprite.cpp b/engines/ags/engine/ac/dynamicsprite.cpp
index 1cafa99166..859e3a5bfa 100644
--- a/engines/ags/engine/ac/dynamicsprite.cpp
+++ b/engines/ags/engine/ac/dynamicsprite.cpp
@@ -20,7 +20,6 @@
  *
  */
 
-//include <math.h>
 #include "ags/engine/ac/dynamicsprite.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/charactercache.h"
@@ -40,18 +39,18 @@
 #include "ags/shared/ac/spritecache.h"
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/engine/script/runtimescriptvalue.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace Shared;
 using namespace Engine;
 
-extern GameSetupStruct game;
-extern SpriteCache spriteset;
+
+
 extern RoomStruct thisroom;
 extern RoomObject *objs;
 extern RoomStatus *croom;
@@ -76,7 +75,7 @@ ScriptDrawingSurface *DynamicSprite_GetDrawingSurface(ScriptDynamicSprite *dss)
 	ScriptDrawingSurface *surface = new ScriptDrawingSurface();
 	surface->dynamicSpriteNumber = dss->slot;
 
-	if ((game.SpriteInfos[dss->slot].Flags & SPF_ALPHACHANNEL) != 0)
+	if ((_GP(game).SpriteInfos[dss->slot].Flags & SPF_ALPHACHANNEL) != 0)
 		surface->hasAlphaChannel = true;
 
 	ccRegisterManagedObject(surface, surface);
@@ -90,15 +89,15 @@ int DynamicSprite_GetGraphic(ScriptDynamicSprite *sds) {
 }
 
 int DynamicSprite_GetWidth(ScriptDynamicSprite *sds) {
-	return game_to_data_coord(game.SpriteInfos[sds->slot].Width);
+	return game_to_data_coord(_GP(game).SpriteInfos[sds->slot].Width);
 }
 
 int DynamicSprite_GetHeight(ScriptDynamicSprite *sds) {
-	return game_to_data_coord(game.SpriteInfos[sds->slot].Height);
+	return game_to_data_coord(_GP(game).SpriteInfos[sds->slot].Height);
 }
 
 int DynamicSprite_GetColorDepth(ScriptDynamicSprite *sds) {
-	int depth = spriteset[sds->slot]->GetColorDepth();
+	int depth = _GP(spriteset)[sds->slot]->GetColorDepth();
 	if (depth == 15)
 		depth = 16;
 	if (depth == 24)
@@ -118,15 +117,15 @@ void DynamicSprite_Resize(ScriptDynamicSprite *sds, int width, int height) {
 		quitprintf("!DynamicSprite.Resize: new size is too large: %d x %d", width, height);
 
 	// resize the sprite to the requested size
-	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
-	newPic->StretchBlt(spriteset[sds->slot],
-		RectWH(0, 0, game.SpriteInfos[sds->slot].Width, game.SpriteInfos[sds->slot].Height),
+	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, _GP(spriteset)[sds->slot]->GetColorDepth());
+	newPic->StretchBlt(_GP(spriteset)[sds->slot],
+		RectWH(0, 0, _GP(game).SpriteInfos[sds->slot].Width, _GP(game).SpriteInfos[sds->slot].Height),
 		RectWH(0, 0, width, height));
 
-	delete spriteset[sds->slot];
+	delete _GP(spriteset)[sds->slot];
 
 	// replace the bitmap in the sprite set
-	add_dynamic_sprite(sds->slot, newPic, (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
+	add_dynamic_sprite(sds->slot, newPic, (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void DynamicSprite_Flip(ScriptDynamicSprite *sds, int direction) {
@@ -136,43 +135,43 @@ void DynamicSprite_Flip(ScriptDynamicSprite *sds, int direction) {
 		quit("!DynamicSprite.Flip: sprite has been deleted");
 
 	// resize the sprite to the requested size
-	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(game.SpriteInfos[sds->slot].Width, game.SpriteInfos[sds->slot].Height, spriteset[sds->slot]->GetColorDepth());
+	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(_GP(game).SpriteInfos[sds->slot].Width, _GP(game).SpriteInfos[sds->slot].Height, _GP(spriteset)[sds->slot]->GetColorDepth());
 
 	if (direction == 1)
-		newPic->FlipBlt(spriteset[sds->slot], 0, 0, Shared::kBitmap_HFlip);
+		newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, Shared::kBitmap_HFlip);
 	else if (direction == 2)
-		newPic->FlipBlt(spriteset[sds->slot], 0, 0, Shared::kBitmap_VFlip);
+		newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, Shared::kBitmap_VFlip);
 	else if (direction == 3)
-		newPic->FlipBlt(spriteset[sds->slot], 0, 0, Shared::kBitmap_HVFlip);
+		newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, Shared::kBitmap_HVFlip);
 
-	delete spriteset[sds->slot];
+	delete _GP(spriteset)[sds->slot];
 
 	// replace the bitmap in the sprite set
-	add_dynamic_sprite(sds->slot, newPic, (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
+	add_dynamic_sprite(sds->slot, newPic, (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void DynamicSprite_CopyTransparencyMask(ScriptDynamicSprite *sds, int sourceSprite) {
 	if (sds->slot == 0)
 		quit("!DynamicSprite.CopyTransparencyMask: sprite has been deleted");
 
-	if ((game.SpriteInfos[sds->slot].Width != game.SpriteInfos[sourceSprite].Width) ||
-		(game.SpriteInfos[sds->slot].Height != game.SpriteInfos[sourceSprite].Height)) {
+	if ((_GP(game).SpriteInfos[sds->slot].Width != _GP(game).SpriteInfos[sourceSprite].Width) ||
+		(_GP(game).SpriteInfos[sds->slot].Height != _GP(game).SpriteInfos[sourceSprite].Height)) {
 		quit("!DynamicSprite.CopyTransparencyMask: sprites are not the same size");
 	}
 
-	Bitmap *target = spriteset[sds->slot];
-	Bitmap *source = spriteset[sourceSprite];
+	Bitmap *target = _GP(spriteset)[sds->slot];
+	Bitmap *source = _GP(spriteset)[sourceSprite];
 
 	if (target->GetColorDepth() != source->GetColorDepth()) {
 		quit("!DynamicSprite.CopyTransparencyMask: sprites are not the same colour depth");
 	}
 
 	// set the target's alpha channel depending on the source
-	bool dst_has_alpha = (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0;
-	bool src_has_alpha = (game.SpriteInfos[sourceSprite].Flags & SPF_ALPHACHANNEL) != 0;
-	game.SpriteInfos[sds->slot].Flags &= ~SPF_ALPHACHANNEL;
+	bool dst_has_alpha = (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0;
+	bool src_has_alpha = (_GP(game).SpriteInfos[sourceSprite].Flags & SPF_ALPHACHANNEL) != 0;
+	_GP(game).SpriteInfos[sds->slot].Flags &= ~SPF_ALPHACHANNEL;
 	if (src_has_alpha) {
-		game.SpriteInfos[sds->slot].Flags |= SPF_ALPHACHANNEL;
+		_GP(game).SpriteInfos[sds->slot].Flags |= SPF_ALPHACHANNEL;
 	}
 
 	BitmapHelper::CopyTransparency(target, source, dst_has_alpha, src_has_alpha);
@@ -187,14 +186,14 @@ void DynamicSprite_ChangeCanvasSize(ScriptDynamicSprite *sds, int width, int hei
 	data_to_game_coords(&x, &y);
 	data_to_game_coords(&width, &height);
 
-	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
+	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, _GP(spriteset)[sds->slot]->GetColorDepth());
 	// blit it into the enlarged image
-	newPic->Blit(spriteset[sds->slot], 0, 0, x, y, game.SpriteInfos[sds->slot].Width, game.SpriteInfos[sds->slot].Height);
+	newPic->Blit(_GP(spriteset)[sds->slot], 0, 0, x, y, _GP(game).SpriteInfos[sds->slot].Width, _GP(game).SpriteInfos[sds->slot].Height);
 
-	delete spriteset[sds->slot];
+	delete _GP(spriteset)[sds->slot];
 
 	// replace the bitmap in the sprite set
-	add_dynamic_sprite(sds->slot, newPic, (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
+	add_dynamic_sprite(sds->slot, newPic, (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void DynamicSprite_Crop(ScriptDynamicSprite *sds, int x1, int y1, int width, int height) {
@@ -206,17 +205,17 @@ void DynamicSprite_Crop(ScriptDynamicSprite *sds, int x1, int y1, int width, int
 	data_to_game_coords(&x1, &y1);
 	data_to_game_coords(&width, &height);
 
-	if ((width > game.SpriteInfos[sds->slot].Width) || (height > game.SpriteInfos[sds->slot].Height))
+	if ((width > _GP(game).SpriteInfos[sds->slot].Width) || (height > _GP(game).SpriteInfos[sds->slot].Height))
 		quit("!DynamicSprite.Crop: requested to crop an area larger than the source");
 
-	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
+	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, _GP(spriteset)[sds->slot]->GetColorDepth());
 	// blit it cropped
-	newPic->Blit(spriteset[sds->slot], x1, y1, 0, 0, newPic->GetWidth(), newPic->GetHeight());
+	newPic->Blit(_GP(spriteset)[sds->slot], x1, y1, 0, 0, newPic->GetWidth(), newPic->GetHeight());
 
-	delete spriteset[sds->slot];
+	delete _GP(spriteset)[sds->slot];
 
 	// replace the bitmap in the sprite set
-	add_dynamic_sprite(sds->slot, newPic, (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
+	add_dynamic_sprite(sds->slot, newPic, (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void DynamicSprite_Rotate(ScriptDynamicSprite *sds, int angle, int width, int height) {
@@ -237,8 +236,8 @@ void DynamicSprite_Rotate(ScriptDynamicSprite *sds, int angle, int width, int he
 		double sinVal = sin(angleInRadians);
 		double cosVal = cos(angleInRadians);
 
-		width = (cosVal * (double)game.SpriteInfos[sds->slot].Width + sinVal * (double)game.SpriteInfos[sds->slot].Height);
-		height = (sinVal * (double)game.SpriteInfos[sds->slot].Width + cosVal * (double)game.SpriteInfos[sds->slot].Height);
+		width = (cosVal * (double)_GP(game).SpriteInfos[sds->slot].Width + sinVal * (double)_GP(game).SpriteInfos[sds->slot].Height);
+		height = (sinVal * (double)_GP(game).SpriteInfos[sds->slot].Width + cosVal * (double)_GP(game).SpriteInfos[sds->slot].Height);
 	} else {
 		data_to_game_coords(&width, &height);
 	}
@@ -247,28 +246,28 @@ void DynamicSprite_Rotate(ScriptDynamicSprite *sds, int angle, int width, int he
 	angle = (angle * 256) / 360;
 
 	// resize the sprite to the requested size
-	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
+	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, _GP(spriteset)[sds->slot]->GetColorDepth());
 
 	// rotate the sprite about its centre
 	// (+ width%2 fixes one pixel offset problem)
-	newPic->RotateBlt(spriteset[sds->slot], width / 2 + width % 2, height / 2,
-		game.SpriteInfos[sds->slot].Width / 2, game.SpriteInfos[sds->slot].Height / 2, itofix(angle));
+	newPic->RotateBlt(_GP(spriteset)[sds->slot], width / 2 + width % 2, height / 2,
+		_GP(game).SpriteInfos[sds->slot].Width / 2, _GP(game).SpriteInfos[sds->slot].Height / 2, itofix(angle));
 
-	delete spriteset[sds->slot];
+	delete _GP(spriteset)[sds->slot];
 
 	// replace the bitmap in the sprite set
-	add_dynamic_sprite(sds->slot, newPic, (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
+	add_dynamic_sprite(sds->slot, newPic, (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void DynamicSprite_Tint(ScriptDynamicSprite *sds, int red, int green, int blue, int saturation, int luminance) {
-	Bitmap *source = spriteset[sds->slot];
+	Bitmap *source = _GP(spriteset)[sds->slot];
 	Bitmap *newPic = BitmapHelper::CreateBitmap(source->GetWidth(), source->GetHeight(), source->GetColorDepth());
 
 	tint_image(newPic, source, red, green, blue, saturation, (luminance * 25) / 10);
 
 	delete source;
 	// replace the bitmap in the sprite set
-	add_dynamic_sprite(sds->slot, newPic, (game.SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
+	add_dynamic_sprite(sds->slot, newPic, (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 int DynamicSprite_SaveToFile(ScriptDynamicSprite *sds, const char *namm) {
@@ -282,7 +281,7 @@ int DynamicSprite_SaveToFile(ScriptDynamicSprite *sds, const char *namm) {
 	ResolvedPath rp;
 	if (!ResolveWritePathAndCreateDirs(filename, rp))
 		return 0;
-	return spriteset[sds->slot]->SaveToFile(rp.FullPath, palette) ? 1 : 0;
+	return _GP(spriteset)[sds->slot]->SaveToFile(rp.FullPath, palette) ? 1 : 0;
 }
 
 ScriptDynamicSprite *DynamicSprite_CreateFromSaveGame(int sgslot, int width, int height) {
@@ -307,7 +306,7 @@ ScriptDynamicSprite *DynamicSprite_CreateFromScreenShot(int width, int height) {
 
 	// TODO: refactor and merge with create_savegame_screenshot()
 
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return nullptr;
 
@@ -334,19 +333,19 @@ ScriptDynamicSprite *DynamicSprite_CreateFromScreenShot(int width, int height) {
 
 ScriptDynamicSprite *DynamicSprite_CreateFromExistingSprite(int slot, int preserveAlphaChannel) {
 
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return nullptr;
 
-	if (!spriteset.DoesSpriteExist(slot))
+	if (!_GP(spriteset).DoesSpriteExist(slot))
 		quitprintf("DynamicSprite.CreateFromExistingSprite: sprite %d does not exist", slot);
 
 	// create a new sprite as a copy of the existing one
-	Bitmap *newPic = BitmapHelper::CreateBitmapCopy(spriteset[slot]);
+	Bitmap *newPic = BitmapHelper::CreateBitmapCopy(_GP(spriteset)[slot]);
 	if (newPic == nullptr)
 		return nullptr;
 
-	bool hasAlpha = (preserveAlphaChannel) && ((game.SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
+	bool hasAlpha = (preserveAlphaChannel) && ((_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
 
 	// replace the bitmap in the sprite set
 	add_dynamic_sprite(gotSlot, newPic, hasAlpha);
@@ -355,7 +354,7 @@ ScriptDynamicSprite *DynamicSprite_CreateFromExistingSprite(int slot, int preser
 }
 
 ScriptDynamicSprite *DynamicSprite_CreateFromDrawingSurface(ScriptDrawingSurface *sds, int x, int y, int width, int height) {
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return nullptr;
 
@@ -386,15 +385,15 @@ ScriptDynamicSprite *DynamicSprite_CreateFromDrawingSurface(ScriptDrawingSurface
 ScriptDynamicSprite *DynamicSprite_Create(int width, int height, int alphaChannel) {
 	data_to_game_coords(&width, &height);
 
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return nullptr;
 
-	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, game.GetColorDepth());
+	Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, _GP(game).GetColorDepth());
 	if (newPic == nullptr)
 		return nullptr;
 
-	if ((alphaChannel) && (game.GetColorDepth() < 32))
+	if ((alphaChannel) && (_GP(game).GetColorDepth() < 32))
 		alphaChannel = false;
 
 	add_dynamic_sprite(gotSlot, ReplaceBitmapWithSupportedFormat(newPic), alphaChannel != 0);
@@ -425,7 +424,7 @@ ScriptDynamicSprite *DynamicSprite_CreateFromBackground(int frame, int x1, int y
 	data_to_game_coords(&x1, &y1);
 	data_to_game_coords(&width, &height);
 
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return nullptr;
 
@@ -446,35 +445,35 @@ ScriptDynamicSprite *DynamicSprite_CreateFromBackground(int frame, int x1, int y
 
 void add_dynamic_sprite(int gotSlot, Bitmap *redin, bool hasAlpha) {
 
-	spriteset.SetSprite(gotSlot, redin);
+	_GP(spriteset).SetSprite(gotSlot, redin);
 
-	game.SpriteInfos[gotSlot].Flags = SPF_DYNAMICALLOC;
+	_GP(game).SpriteInfos[gotSlot].Flags = SPF_DYNAMICALLOC;
 
 	if (redin->GetColorDepth() > 8)
-		game.SpriteInfos[gotSlot].Flags |= SPF_HICOLOR;
+		_GP(game).SpriteInfos[gotSlot].Flags |= SPF_HICOLOR;
 	if (redin->GetColorDepth() > 16)
-		game.SpriteInfos[gotSlot].Flags |= SPF_TRUECOLOR;
+		_GP(game).SpriteInfos[gotSlot].Flags |= SPF_TRUECOLOR;
 	if (hasAlpha)
-		game.SpriteInfos[gotSlot].Flags |= SPF_ALPHACHANNEL;
+		_GP(game).SpriteInfos[gotSlot].Flags |= SPF_ALPHACHANNEL;
 
-	game.SpriteInfos[gotSlot].Width = redin->GetWidth();
-	game.SpriteInfos[gotSlot].Height = redin->GetHeight();
+	_GP(game).SpriteInfos[gotSlot].Width = redin->GetWidth();
+	_GP(game).SpriteInfos[gotSlot].Height = redin->GetHeight();
 }
 
 void free_dynamic_sprite(int gotSlot) {
 	int tt;
 
-	if ((gotSlot < 0) || (gotSlot >= spriteset.GetSpriteSlotCount()))
+	if ((gotSlot < 0) || (gotSlot >= _GP(spriteset).GetSpriteSlotCount()))
 		quit("!FreeDynamicSprite: invalid slot number");
 
-	if ((game.SpriteInfos[gotSlot].Flags & SPF_DYNAMICALLOC) == 0)
+	if ((_GP(game).SpriteInfos[gotSlot].Flags & SPF_DYNAMICALLOC) == 0)
 		quitprintf("!DeleteSprite: Attempted to free static sprite %d that was not loaded by the script", gotSlot);
 
-	spriteset.RemoveSprite(gotSlot, true);
+	_GP(spriteset).RemoveSprite(gotSlot, true);
 
-	game.SpriteInfos[gotSlot].Flags = 0;
-	game.SpriteInfos[gotSlot].Width = 0;
-	game.SpriteInfos[gotSlot].Height = 0;
+	_GP(game).SpriteInfos[gotSlot].Flags = 0;
+	_GP(game).SpriteInfos[gotSlot].Width = 0;
+	_GP(game).SpriteInfos[gotSlot].Height = 0;
 
 	// ensure it isn't still on any GUI buttons
 	for (tt = 0; tt < numguibuts; tt++) {
diff --git a/engines/ags/engine/ac/dynobj/cc_audioclip.cpp b/engines/ags/engine/ac/dynobj/cc_audioclip.cpp
index 01351f4eef..c686767542 100644
--- a/engines/ags/engine/ac/dynobj/cc_audioclip.cpp
+++ b/engines/ags/engine/ac/dynobj/cc_audioclip.cpp
@@ -23,11 +23,10 @@
 #include "ags/engine/ac/dynobj/cc_audioclip.h"
 #include "ags/shared/ac/dynobj/scriptaudioclip.h"
 #include "ags/shared/ac/gamesetupstruct.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
-
 const char *CCAudioClip::GetType() {
 	return "AudioClip";
 }
@@ -42,7 +41,7 @@ int CCAudioClip::Serialize(const char *address, char *buffer, int bufsize) {
 void CCAudioClip::Unserialize(int index, const char *serializedData, int dataSize) {
 	StartUnserialize(serializedData, dataSize);
 	int id = UnserializeInt();
-	ccRegisterUnserializedObject(index, &game.audioClips[id], this);
+	ccRegisterUnserializedObject(index, &_GP(game).audioClips[id], this);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/dynobj/cc_character.cpp b/engines/ags/engine/ac/dynobj/cc_character.cpp
index a4a03ad253..3e34c13e77 100644
--- a/engines/ags/engine/ac/dynobj/cc_character.cpp
+++ b/engines/ags/engine/ac/dynobj/cc_character.cpp
@@ -25,11 +25,10 @@
 #include "ags/engine/ac/global_character.h"
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/shared/ac/game_version.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
-
 // return the type name of the object
 const char *CCCharacter::GetType() {
 	return "Character";
@@ -47,7 +46,7 @@ int CCCharacter::Serialize(const char *address, char *buffer, int bufsize) {
 void CCCharacter::Unserialize(int index, const char *serializedData, int dataSize) {
 	StartUnserialize(serializedData, dataSize);
 	int num = UnserializeInt();
-	ccRegisterUnserializedObject(index, &game.chars[num], this);
+	ccRegisterUnserializedObject(index, &_GP(game).chars[num], this);
 }
 
 void CCCharacter::WriteInt16(const char *address, intptr_t offset, int16_t val) {
diff --git a/engines/ags/engine/ac/dynobj/scriptdrawingsurface.cpp b/engines/ags/engine/ac/dynobj/scriptdrawingsurface.cpp
index 4c19c95c67..c3f68fdf29 100644
--- a/engines/ags/engine/ac/dynobj/scriptdrawingsurface.cpp
+++ b/engines/ags/engine/ac/dynobj/scriptdrawingsurface.cpp
@@ -29,23 +29,23 @@
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/shared/game/roomstruct.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
 extern RoomStruct thisroom;
-extern SpriteCache spriteset;
+
 extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
 extern GameState play;
-extern GameSetupStruct game;
 
 Bitmap *ScriptDrawingSurface::GetBitmapSurface() {
 	// TODO: consider creating weak_ptr here, and store one in the DrawingSurface!
 	if (roomBackgroundNumber >= 0)
 		return thisroom.BgFrames[roomBackgroundNumber].Graphic.get();
 	else if (dynamicSpriteNumber >= 0)
-		return spriteset[dynamicSpriteNumber];
+		return _GP(spriteset)[dynamicSpriteNumber];
 	else if (dynamicSurfaceNumber >= 0)
 		return dynamicallyCreatedSurfaces[dynamicSurfaceNumber];
 	else if (linkedBitmapOnly != nullptr)
@@ -127,7 +127,7 @@ ScriptDrawingSurface::ScriptDrawingSurface() {
 	// NOTE: Normally in contemporary games coordinates ratio will always be 1:1.
 	// But we still support legacy drawing, so have to set this up even for modern games,
 	// otherwise we'd have to complicate conversion conditions further.
-	if (game.IsLegacyHiRes() && game.IsDataInNativeCoordinates()) {
+	if (_GP(game).IsLegacyHiRes() && _GP(game).IsDataInNativeCoordinates()) {
 		highResCoordinates = 1;
 	}
 }
diff --git a/engines/ags/engine/ac/event.cpp b/engines/ags/engine/ac/event.cpp
index 8e2672d3a7..aefcc02683 100644
--- a/engines/ags/engine/ac/event.cpp
+++ b/engines/ags/engine/ac/event.cpp
@@ -41,13 +41,14 @@
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/ac/timer.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern RoomStruct thisroom;
 extern RoomStatus *croom;
 extern int displayed_room;
@@ -124,9 +125,9 @@ void run_room_event(int id) {
 void run_event_block_inv(int invNum, int event_) {
 	evblockbasename = "inventory%d";
 	if (loaded_game_file_version > kGameVersion_272) {
-		run_interaction_script(game.invScripts[invNum].get(), event_);
+		run_interaction_script(_GP(game).invScripts[invNum].get(), event_);
 	} else {
-		run_interaction_event(game.intrInv[invNum].get(), event_);
+		run_interaction_event(_GP(game).intrInv[invNum].get(), event_);
 	}
 
 }
@@ -137,7 +138,7 @@ void setevent(int evtyp, int ev1, int ev2, int ev3) {
 	event[numevents].data1 = ev1;
 	event[numevents].data2 = ev2;
 	event[numevents].data3 = ev3;
-	event[numevents].player = game.playercharacter;
+	event[numevents].player = _GP(game).playercharacter;
 	numevents++;
 	if (numevents >= MAXEVENTS) quit("too many events posted");
 }
@@ -238,7 +239,7 @@ void process_event(EventHappened *evp) {
 		}
 
 		// TODO: use normal coordinates instead of "native_size" and multiply_up_*?
-		//const Size &data_res = game.GetDataRes();
+		//const Size &data_res = _GP(game).GetDataRes();
 		const Rect &viewport = play.GetMainViewport();
 
 		if ((theTransition == FADE_INSTANT) || ignore_transition)
@@ -282,7 +283,7 @@ void process_event(EventHappened *evp) {
 			}
 			play.screen_is_faded_out = 0;
 		} else if (theTransition == FADE_CROSSFADE) {
-			if (game.color_depth == 1)
+			if (_GP(game).color_depth == 1)
 				quit("!Cannot use crossfade screen transition in 256-colour games");
 
 			IDriverDependantBitmap *ddb = prepare_screen_for_transition_in();
@@ -320,7 +321,7 @@ void process_event(EventHappened *evp) {
 			IDriverDependantBitmap *ddb = prepare_screen_for_transition_in();
 			for (aa = 0; aa < 16; aa++) {
 				// merge the palette while dithering
-				if (game.color_depth == 1) {
+				if (_GP(game).color_depth == 1) {
 					fade_interpolate(old_palette, palette, interpal, aa * 4, 0, 255);
 					set_palette_range(interpal, 0, 255, 0);
 				}
@@ -358,7 +359,7 @@ void runevent_now(int evtyp, int ev1, int ev2, int ev3) {
 	evh.data1 = ev1;
 	evh.data2 = ev2;
 	evh.data3 = ev3;
-	evh.player = game.playercharacter;
+	evh.player = _GP(game).playercharacter;
 	process_event(&evh);
 }
 
diff --git a/engines/ags/engine/ac/file.cpp b/engines/ags/engine/ac/file.cpp
index a63329e06c..f8a52411a0 100644
--- a/engines/ags/engine/ac/file.cpp
+++ b/engines/ags/engine/ac/file.cpp
@@ -45,18 +45,18 @@
 #include "ags/shared/util/path.h"
 #include "ags/shared/util/string.h"
 #include "ags/shared/util/string_utils.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
 extern GameSetup usetup;
-extern GameSetupStruct game;
+
 extern AGSPlatformDriver *platform;
 
 extern int MAXSTRLEN;
@@ -265,7 +265,7 @@ String MakeSpecialSubDir(const String &sp_dir) {
 	String full_path = sp_dir;
 	if (full_path.GetLast() != '/' && full_path.GetLast() != '\\')
 		full_path.AppendChar('/');
-	full_path.Append(game.saveGameFolderName);
+	full_path.Append(_GP(game).saveGameFolderName);
 	Directory::CreateDirectory(full_path);
 	return full_path;
 }
@@ -554,7 +554,7 @@ AssetPath get_audio_clip_assetpath(int bundling_type, const String &filename) {
 	if (bundling_type == AUCL_BUNDLE_EXE)
 		return AssetPath(ResPaths.GamePak.Name, filename);
 	else if (bundling_type == AUCL_BUNDLE_VOX)
-		return AssetPath(game.GetAudioVOXName(), filename);
+		return AssetPath(_GP(game).GetAudioVOXName(), filename);
 	return AssetPath();
 }
 
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index 37967c343c..300d26923f 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -21,7 +21,6 @@
  */
 
 #include "ags/engine/ac/game.h"
-
 #include "ags/shared/ac/common.h"
 #include "ags/shared/ac/view.h"
 #include "ags/shared/ac/audiocliptype.h"
@@ -101,6 +100,7 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 #include "common/memstream.h"
 
@@ -151,7 +151,6 @@ extern IGraphicsDriver *gfxDriver;
 //=============================================================================
 GameState play;
 GameSetup usetup;
-GameSetupStruct game;
 RoomStatus troom;    // used for non-saveable rooms, eg. intro
 RoomObject *objs;
 RoomStatus *croom = nullptr;
@@ -168,7 +167,6 @@ int new_room_x = SCR_NO_VALUE, new_room_y = SCR_NO_VALUE;
 int new_room_loop = SCR_NO_VALUE;
 
 // initially size 1, this will be increased by the initFile function
-SpriteCache spriteset(game.SpriteInfos);
 int proper_exit = 0, our_eip = 0;
 
 std::vector<GUIMain> guis;
@@ -225,8 +223,8 @@ int getloctype_index = 0, getloctype_throughgui = 0;
 //=============================================================================
 
 void Game_StopAudio(int audioType) {
-	if (((audioType < 0) || ((size_t)audioType >= game.audioClipTypes.size())) && (audioType != SCR_NO_VALUE))
-		quitprintf("!Game.StopAudio: invalid audio type %d", audioType);
+	if (((audioType < 0) || ((size_t)audioType >= _GP(game).audioClipTypes.size())) && (audioType != SCR_NO_VALUE))
+		quitprintf("!_GP(game).StopAudio: invalid audio type %d", audioType);
 	int aa;
 
 	for (aa = 0; aa < MAX_SOUND_CHANNELS; aa++) {
@@ -243,8 +241,8 @@ void Game_StopAudio(int audioType) {
 }
 
 int Game_IsAudioPlaying(int audioType) {
-	if (((audioType < 0) || ((size_t)audioType >= game.audioClipTypes.size())) && (audioType != SCR_NO_VALUE))
-		quitprintf("!Game.IsAudioPlaying: invalid audio type %d", audioType);
+	if (((audioType < 0) || ((size_t)audioType >= _GP(game).audioClipTypes.size())) && (audioType != SCR_NO_VALUE))
+		quitprintf("!_GP(game).IsAudioPlaying: invalid audio type %d", audioType);
 
 	if (play.fast_forward)
 		return 0;
@@ -261,21 +259,21 @@ int Game_IsAudioPlaying(int audioType) {
 }
 
 void Game_SetAudioTypeSpeechVolumeDrop(int audioType, int volumeDrop) {
-	if ((audioType < 0) || ((size_t)audioType >= game.audioClipTypes.size()))
-		quitprintf("!Game.SetAudioTypeVolume: invalid audio type: %d", audioType);
+	if ((audioType < 0) || ((size_t)audioType >= _GP(game).audioClipTypes.size()))
+		quitprintf("!_GP(game).SetAudioTypeVolume: invalid audio type: %d", audioType);
 
-	Debug::Printf("Game.SetAudioTypeSpeechVolumeDrop: type: %d, drop: %d", audioType, volumeDrop);
-	game.audioClipTypes[audioType].volume_reduction_while_speech_playing = volumeDrop;
+	Debug::Printf("_GP(game).SetAudioTypeSpeechVolumeDrop: type: %d, drop: %d", audioType, volumeDrop);
+	_GP(game).audioClipTypes[audioType].volume_reduction_while_speech_playing = volumeDrop;
 	update_volume_drop_if_voiceover();
 }
 
 void Game_SetAudioTypeVolume(int audioType, int volume, int changeType) {
 	if ((volume < 0) || (volume > 100))
-		quitprintf("!Game.SetAudioTypeVolume: volume %d is not between 0..100", volume);
-	if ((audioType < 0) || ((size_t)audioType >= game.audioClipTypes.size()))
-		quitprintf("!Game.SetAudioTypeVolume: invalid audio type: %d", audioType);
+		quitprintf("!_GP(game).SetAudioTypeVolume: volume %d is not between 0..100", volume);
+	if ((audioType < 0) || ((size_t)audioType >= _GP(game).audioClipTypes.size()))
+		quitprintf("!_GP(game).SetAudioTypeVolume: invalid audio type: %d", audioType);
 
-	Debug::Printf("Game.SetAudioTypeVolume: type: %d, volume: %d, change: %d", audioType, volume, changeType);
+	Debug::Printf("_GP(game).SetAudioTypeVolume: type: %d, volume: %d, change: %d", audioType, volume, changeType);
 	if ((changeType == VOL_CHANGEEXISTING) ||
 	        (changeType == VOL_BOTH)) {
 		AudioChannelsLock lock;
@@ -312,7 +310,7 @@ int Game_GetMODPattern() {
 //=============================================================================
 
 int Game_GetDialogCount() {
-	return game.numdialog;
+	return _GP(game).numdialog;
 }
 
 void set_debug_mode(bool on) {
@@ -401,13 +399,13 @@ bool MakeSaveGameDir(const String &newFolder, ResolvedPath &rp) {
 		// safe save path with default name
 		if (saveGameParent.IsEmpty()) {
 			base_dir = PathOrCurDir(platform->GetUserSavedgamesDirectory());
-			newSaveGameDir.Format("%s/%s/%s", base_dir.GetCStr(), game.saveGameFolderName, newFolder.GetCStr());
+			newSaveGameDir.Format("%s/%s/%s", base_dir.GetCStr(), _GP(game).saveGameFolderName, newFolder.GetCStr());
 		} else {
 			base_dir = saveGameParent;
 			newSaveGameDir.Format("%s/%s", saveGameParent.GetCStr(), newFolder.GetCStr());
 		}
 		// For games made in the safe-path-aware versions of AGS, report a warning
-		if (game.options[OPT_SAFEFILEPATHS]) {
+		if (_GP(game).options[OPT_SAFEFILEPATHS]) {
 			debug_script_warn("Attempt to explicitly set savegame location relative to the game installation directory ('%s') denied;\nPath will be remapped to the user documents directory: '%s'",
 			                  newFolder.GetCStr(), newSaveGameDir.GetCStr());
 		}
@@ -595,7 +593,7 @@ void unload_game_file() {
 		curLipLine = -1;
 	}
 
-	for (int i = 0; i < game.numdialog; ++i) {
+	for (int i = 0; i < _GP(game).numdialog; ++i) {
 		if (dialog[i].optionscripts != nullptr)
 			free(dialog[i].optionscripts);
 		dialog[i].optionscripts = nullptr;
@@ -605,7 +603,7 @@ void unload_game_file() {
 	delete[] scrDialog;
 	scrDialog = nullptr;
 
-	for (int i = 0; i < game.numgui; ++i) {
+	for (int i = 0; i < _GP(game).numgui; ++i) {
 		free(guibg[i]);
 		guibg[i] = nullptr;
 	}
@@ -627,7 +625,7 @@ void unload_game_file() {
 	resetRoomStatuses();
 
 	// free game struct last because it contains object counts
-	game.Free();
+	_GP(game).Free();
 }
 
 
@@ -637,7 +635,7 @@ void unload_game_file() {
 
 const char *Game_GetGlobalStrings(int index) {
 	if ((index < 0) || (index >= MAXGLOBALSTRINGS))
-		quit("!Game.GlobalStrings: invalid index");
+		quit("!_GP(game).GlobalStrings: invalid index");
 
 	return CreateNewScriptString(play.globalstrings[index]);
 }
@@ -651,62 +649,62 @@ char gamefilenamebuf[200];
 
 int Game_GetInventoryItemCount() {
 	// because of the dummy item 0, this is always one higher than it should be
-	return game.numinvitems - 1;
+	return _GP(game).numinvitems - 1;
 }
 
 int Game_GetFontCount() {
-	return game.numfonts;
+	return _GP(game).numfonts;
 }
 
 int Game_GetMouseCursorCount() {
-	return game.numcursors;
+	return _GP(game).numcursors;
 }
 
 int Game_GetCharacterCount() {
-	return game.numcharacters;
+	return _GP(game).numcharacters;
 }
 
 int Game_GetGUICount() {
-	return game.numgui;
+	return _GP(game).numgui;
 }
 
 int Game_GetViewCount() {
-	return game.numviews;
+	return _GP(game).numviews;
 }
 
 int Game_GetUseNativeCoordinates() {
-	return game.IsDataInNativeCoordinates() ? 1 : 0;
+	return _GP(game).IsDataInNativeCoordinates() ? 1 : 0;
 }
 
 int Game_GetSpriteWidth(int spriteNum) {
 	if (spriteNum < 0)
 		return 0;
 
-	if (!spriteset.DoesSpriteExist(spriteNum))
+	if (!_GP(spriteset).DoesSpriteExist(spriteNum))
 		return 0;
 
-	return game_to_data_coord(game.SpriteInfos[spriteNum].Width);
+	return game_to_data_coord(_GP(game).SpriteInfos[spriteNum].Width);
 }
 
 int Game_GetSpriteHeight(int spriteNum) {
 	if (spriteNum < 0)
 		return 0;
 
-	if (!spriteset.DoesSpriteExist(spriteNum))
+	if (!_GP(spriteset).DoesSpriteExist(spriteNum))
 		return 0;
 
-	return game_to_data_coord(game.SpriteInfos[spriteNum].Height);
+	return game_to_data_coord(_GP(game).SpriteInfos[spriteNum].Height);
 }
 
 int Game_GetLoopCountForView(int viewNumber) {
-	if ((viewNumber < 1) || (viewNumber > game.numviews))
+	if ((viewNumber < 1) || (viewNumber > _GP(game).numviews))
 		quit("!GetGameParameter: invalid view specified");
 
 	return views[viewNumber - 1].numLoops;
 }
 
 int Game_GetRunNextSettingForLoop(int viewNumber, int loopNumber) {
-	if ((viewNumber < 1) || (viewNumber > game.numviews))
+	if ((viewNumber < 1) || (viewNumber > _GP(game).numviews))
 		quit("!GetGameParameter: invalid view specified");
 	if ((loopNumber < 0) || (loopNumber >= views[viewNumber - 1].numLoops))
 		quit("!GetGameParameter: invalid loop specified");
@@ -715,7 +713,7 @@ int Game_GetRunNextSettingForLoop(int viewNumber, int loopNumber) {
 }
 
 int Game_GetFrameCountForLoop(int viewNumber, int loopNumber) {
-	if ((viewNumber < 1) || (viewNumber > game.numviews))
+	if ((viewNumber < 1) || (viewNumber > _GP(game).numviews))
 		quit("!GetGameParameter: invalid view specified");
 	if ((loopNumber < 0) || (loopNumber >= views[viewNumber - 1].numLoops))
 		quit("!GetGameParameter: invalid loop specified");
@@ -724,7 +722,7 @@ int Game_GetFrameCountForLoop(int viewNumber, int loopNumber) {
 }
 
 ScriptViewFrame *Game_GetViewFrame(int viewNumber, int loopNumber, int frame) {
-	if ((viewNumber < 1) || (viewNumber > game.numviews))
+	if ((viewNumber < 1) || (viewNumber > _GP(game).numviews))
 		quit("!GetGameParameter: invalid view specified");
 	if ((loopNumber < 0) || (loopNumber >= views[viewNumber - 1].numLoops))
 		quit("!GetGameParameter: invalid loop specified");
@@ -752,7 +750,7 @@ int Game_GetTextReadingSpeed() {
 
 void Game_SetTextReadingSpeed(int newTextSpeed) {
 	if (newTextSpeed < 1)
-		quitprintf("!Game.TextReadingSpeed: %d is an invalid speed", newTextSpeed);
+		quitprintf("!_GP(game).TextReadingSpeed: %d is an invalid speed", newTextSpeed);
 
 	play.text_speed = newTextSpeed;
 }
@@ -806,7 +804,7 @@ int Game_GetColorFromRGB(int red, int grn, int blu) {
 	        (blu < 0) || (blu > 255))
 		quit("!GetColorFromRGB: colour values must be 0-255");
 
-	if (game.color_depth == 1) {
+	if (_GP(game).color_depth == 1) {
 		return makecol8(red, grn, blu);
 	}
 
@@ -872,9 +870,9 @@ int Game_ChangeTranslation(const char *newFilename) {
 }
 
 ScriptAudioClip *Game_GetAudioClip(int index) {
-	if (index < 0 || (size_t)index >= game.audioClips.size())
+	if (index < 0 || (size_t)index >= _GP(game).audioClips.size())
 		return nullptr;
-	return &game.audioClips[index];
+	return &_GP(game).audioClips[index];
 }
 
 ScriptCamera *Game_GetCamera() {
@@ -1012,7 +1010,7 @@ long write_screen_shot_for_vista(Stream *out, Bitmap *screenshot) {
 
 void WriteGameSetupStructBase_Aligned(Stream *out) {
 	AlignedStream align_s(out, Shared::kAligned_Write);
-	game.GameSetupStructBase::WriteToFile(&align_s);
+	_GP(game).GameSetupStructBase::WriteToFile(&align_s);
 }
 
 #define MAGICNUMBER 0xbeefcafe
@@ -1020,7 +1018,7 @@ void WriteGameSetupStructBase_Aligned(Stream *out) {
 void create_savegame_screenshot(Bitmap *&screenShot) {
 	// WORKAROUND: AGS originally only creates savegames if the game flags
 	// that it supports it. But we want it all the time for ScummVM GMM
-	if (/*game.options[OPT_SAVESCREENSHOT] */true) {
+	if (/*_GP(game).options[OPT_SAVESCREENSHOT] */true) {
 		// Render the view without any UI elements
 		int old_flags = debug_flags;
 		debug_flags |= DBG_NOIFACE;
@@ -1035,7 +1033,7 @@ void create_savegame_screenshot(Bitmap *&screenShot) {
 			usehit = viewport.GetHeight();
 
 		if ((play.screenshot_width < 16) || (play.screenshot_height < 16))
-			quit("!Invalid game.screenshot_width/height, must be from 16x16 to screen res");
+			quit("!Invalid _GP(game).screenshot_width/height, must be from 16x16 to screen res");
 
 		screenShot = CopyScreenIntoBitmap(usewid, usehit);
 
@@ -1056,7 +1054,7 @@ void save_game(int slotn, const char *descript) {
 	}
 
 	if (platform->GetDiskFreeSpaceMB() < 2) {
-		Display("ERROR: There is not enough disk space free to save the game. Clear some disk space and try again.");
+		Display("ERROR: There is not enough disk space free to save the _GP(game). Clear some disk space and try again.");
 		return;
 	}
 
@@ -1105,13 +1103,13 @@ HSaveError restore_game_head_dynamic_values(Stream *in, RestoredData &r_data) {
 void restore_game_spriteset(Stream *in) {
 	// ensure the sprite set is at least as large as it was
 	// when the game was saved
-	spriteset.EnlargeTo(in->ReadInt32() - 1); // they saved top_index + 1
+	_GP(spriteset).EnlargeTo(in->ReadInt32() - 1); // they saved top_index + 1
 	// get serialized dynamic sprites
 	int sprnum = in->ReadInt32();
 	while (sprnum) {
 		unsigned char spriteflag = in->ReadByte();
 		add_dynamic_sprite(sprnum, read_serialized_bitmap(in));
-		game.SpriteInfos[sprnum].Flags = spriteflag;
+		_GP(game).SpriteInfos[sprnum].Flags = spriteflag;
 		sprnum = in->ReadInt32();
 	}
 }
@@ -1184,7 +1182,7 @@ void restore_game_play_ex_data(Stream *in) {
 		play.do_once_tokens[i] = rbuffer;
 	}
 
-	in->ReadArrayOfInt32(&play.gui_draw_order[0], game.numgui);
+	in->ReadArrayOfInt32(&play.gui_draw_order[0], _GP(game).numgui);
 }
 
 void restore_game_play(Stream *in, RestoredData &r_data) {
@@ -1205,7 +1203,7 @@ void restore_game_play(Stream *in, RestoredData &r_data) {
 
 void ReadMoveList_Aligned(Stream *in) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
-	for (int i = 0; i < game.numcharacters + MAX_ROOM_OBJECTS + 1; ++i) {
+	for (int i = 0; i < _GP(game).numcharacters + MAX_ROOM_OBJECTS + 1; ++i) {
 		mls[i].ReadFromFile_Legacy(&align_s);
 
 		align_s.Reset();
@@ -1214,12 +1212,12 @@ void ReadMoveList_Aligned(Stream *in) {
 
 void ReadGameSetupStructBase_Aligned(Stream *in) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
-	game.GameSetupStructBase::ReadFromFile(&align_s);
+	_GP(game).GameSetupStructBase::ReadFromFile(&align_s);
 }
 
 void ReadCharacterExtras_Aligned(Stream *in) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
-	for (int i = 0; i < game.numcharacters; ++i) {
+	for (int i = 0; i < _GP(game).numcharacters; ++i) {
 		charextra[i].ReadFromFile(&align_s);
 		align_s.Reset();
 	}
@@ -1230,7 +1228,7 @@ void restore_game_palette(Stream *in) {
 }
 
 void restore_game_dialogs(Stream *in) {
-	for (int vv = 0; vv < game.numdialog; vv++)
+	for (int vv = 0; vv < _GP(game).numdialog; vv++)
 		in->ReadArrayOfInt32(&dialog[vv].optionflags[0], MAXTOPICOPTIONS);
 }
 
@@ -1254,9 +1252,9 @@ HSaveError restore_game_gui(Stream *in, int numGuisWas) {
 	HError err = GUI::ReadGUI(guis, in, true);
 	if (!err)
 		return new SavegameError(kSvgErr_GameObjectInitFailed, err);
-	game.numgui = guis.size();
+	_GP(game).numgui = guis.size();
 
-	if (numGuisWas != game.numgui) {
+	if (numGuisWas != _GP(game).numgui) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of GUI.");
 	}
 
@@ -1266,12 +1264,12 @@ HSaveError restore_game_gui(Stream *in, int numGuisWas) {
 }
 
 HSaveError restore_game_audiocliptypes(Stream *in) {
-	if (in->ReadInt32() != (int)game.audioClipTypes.size()) {
+	if (in->ReadInt32() != (int)_GP(game).audioClipTypes.size()) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Audio Clip Types.");
 	}
 
-	for (size_t i = 0; i < game.audioClipTypes.size(); ++i) {
-		game.audioClipTypes[i].ReadFromFile(in);
+	for (size_t i = 0; i < _GP(game).audioClipTypes.size(); ++i) {
+		_GP(game).audioClipTypes[i].ReadFromFile(in);
 	}
 	return HSaveError::None();
 }
@@ -1369,11 +1367,11 @@ HSaveError restore_game_globalvars(Stream *in) {
 }
 
 HSaveError restore_game_views(Stream *in) {
-	if (in->ReadInt32() != game.numviews) {
+	if (in->ReadInt32() != _GP(game).numviews) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Views.");
 	}
 
-	for (int bb = 0; bb < game.numviews; bb++) {
+	for (int bb = 0; bb < _GP(game).numviews; bb++) {
 		for (int cc = 0; cc < views[bb].numLoops; cc++) {
 			for (int dd = 0; dd < views[bb].loops[cc].numFrames; dd++) {
 				views[bb].loops[cc].frames[dd].sound = in->ReadInt32();
@@ -1385,7 +1383,7 @@ HSaveError restore_game_views(Stream *in) {
 }
 
 HSaveError restore_game_audioclips_and_crossfade(Stream *in, RestoredData &r_data) {
-	if (in->ReadInt32() != (int)game.audioClips.size()) {
+	if (in->ReadInt32() != (int)_GP(game).audioClips.size()) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Audio Clips.");
 	}
 
@@ -1394,7 +1392,7 @@ HSaveError restore_game_audioclips_and_crossfade(Stream *in, RestoredData &r_dat
 		chan_info.Pos = 0;
 		chan_info.ClipID = in->ReadInt32();
 		if (chan_info.ClipID >= 0) {
-			if (chan_info.ClipID >= (int)game.audioClips.size()) {
+			if (chan_info.ClipID >= (int)_GP(game).audioClips.size()) {
 				return new SavegameError(kSvgErr_GameObjectInitFailed, "Invalid audio clip index.");
 			}
 
@@ -1437,39 +1435,39 @@ HSaveError restore_game_data(Stream *in, SavegameVersion svg_version, const Pres
 	ReadMoveList_Aligned(in);
 
 	// save pointer members before reading
-	char *gswas = game.globalscript;
-	ccScript *compsc = game.compiled_script;
-	CharacterInfo *chwas = game.chars;
-	WordsDictionary *olddict = game.dict;
+	char *gswas = _GP(game).globalscript;
+	ccScript *compsc = _GP(game).compiled_script;
+	CharacterInfo *chwas = _GP(game).chars;
+	WordsDictionary *olddict = _GP(game).dict;
 	char *mesbk[MAXGLOBALMES];
-	int numchwas = game.numcharacters;
-	for (vv = 0; vv < MAXGLOBALMES; vv++) mesbk[vv] = game.messages[vv];
-	int numdiwas = game.numdialog;
-	int numinvwas = game.numinvitems;
-	int numviewswas = game.numviews;
-	int numGuisWas = game.numgui;
+	int numchwas = _GP(game).numcharacters;
+	for (vv = 0; vv < MAXGLOBALMES; vv++) mesbk[vv] = _GP(game).messages[vv];
+	int numdiwas = _GP(game).numdialog;
+	int numinvwas = _GP(game).numinvitems;
+	int numviewswas = _GP(game).numviews;
+	int numGuisWas = _GP(game).numgui;
 
 	ReadGameSetupStructBase_Aligned(in);
 
 	// Delete unneeded data
 	// TODO: reorganize this (may be solved by optimizing safe format too)
-	delete [] game.load_messages;
-	game.load_messages = nullptr;
+	delete [] _GP(game).load_messages;
+	_GP(game).load_messages = nullptr;
 
-	if (game.numdialog != numdiwas) {
+	if (_GP(game).numdialog != numdiwas) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Dialogs.");
 	}
-	if (numchwas != game.numcharacters) {
+	if (numchwas != _GP(game).numcharacters) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Characters.");
 	}
-	if (numinvwas != game.numinvitems) {
+	if (numinvwas != _GP(game).numinvitems) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Inventory Items.");
 	}
-	if (game.numviews != numviewswas) {
+	if (_GP(game).numviews != numviewswas) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Views.");
 	}
 
-	game.ReadFromSaveGame_v321(in, gswas, compsc, chwas, olddict, mesbk);
+	_GP(game).ReadFromSaveGame_v321(in, gswas, compsc, chwas, olddict, mesbk);
 
 	// Modified custom properties are read separately to keep existing save format
 	play.ReadCustomProperties_v340(in);
@@ -1552,7 +1550,7 @@ bool read_savedgame_screenshot(const String &savedgame, int &want_shot) {
 		return false;
 
 	if (desc.UserImage.get()) {
-		int slot = spriteset.GetFreeIndex();
+		int slot = _GP(spriteset).GetFreeIndex();
 		if (slot > 0) {
 			// add it into the sprite set
 			add_dynamic_sprite(slot, ReplaceBitmapWithSupportedFormat(desc.UserImage.release()));
@@ -1580,8 +1578,8 @@ HSaveError load_game(int slotNumber, bool &data_overwritten) {
 	if (!err)
 		return err;
 	// CHECKME: is this color depth test still essential? if yes, is there possible workaround?
-	else if (desc.ColorDepth != game.GetColorDepth())
-		return new SavegameError(kSvgErr_DifferentColorDepth, String::FromFormat("Running: %d-bit, saved in: %d-bit.", game.GetColorDepth(), desc.ColorDepth));
+	else if (desc.ColorDepth != _GP(game).GetColorDepth())
+		return new SavegameError(kSvgErr_DifferentColorDepth, String::FromFormat("Running: %d-bit, saved in: %d-bit.", _GP(game).GetColorDepth(), desc.ColorDepth));
 
 	// saved with different game file
 	if (Path::ComparePaths(desc.MainDataFilename, ResPaths.GamePak.Name)) {
@@ -1617,7 +1615,7 @@ bool try_restore_save(int slot) {
 	bool data_overwritten;
 	HSaveError err = load_game(slot, data_overwritten);
 	if (!err) {
-		String error = String::FromFormat("Unable to restore the saved game.\n%s",
+		String error = String::FromFormat("Unable to restore the saved _GP(game).\n%s",
 		                                  err->FullMessage().GetCStr());
 		// currently AGS cannot properly revert to stable state if some of the
 		// game data was released or overwritten by the data from save file,
@@ -1737,7 +1735,7 @@ int __GetLocationType(int xxx, int yyy, int allowHotspot0) {
 	// if it's an Ignore Walkbehinds object, then ignore the walkbehind
 	if ((objat >= 0) && ((objs[objat].flags & OBJF_NOWALKBEHINDS) != 0))
 		wbat = 0;
-	if ((charat >= 0) && ((game.chars[charat].flags & CHF_NOWALKBEHINDS) != 0))
+	if ((charat >= 0) && ((_GP(game).chars[charat].flags & CHF_NOWALKBEHINDS) != 0))
 		wbat = 0;
 
 	if ((charat >= 0) && (objat >= 0)) {
@@ -1849,7 +1847,7 @@ void display_switch_in_resume() {
 
 	// clear the screen if necessary
 	if (gfxDriver && gfxDriver->UsesMemoryBackBuffer())
-		gfxDriver->ClearRectangle(0, 0, game.GetGameRes().Width - 1, game.GetGameRes().Height - 1, nullptr);
+		gfxDriver->ClearRectangle(0, 0, _GP(game).GetGameRes().Width - 1, _GP(game).GetGameRes().Height - 1, nullptr);
 
 	platform->ResumeApplication();
 }
@@ -1875,7 +1873,7 @@ void replace_tokens(const char *srcmes, char *destm, int maxlen) {
 			}
 			char tval[10];
 			if (tokentype == 1) {
-				if ((inx < 1) | (inx >= game.numinvitems))
+				if ((inx < 1) | (inx >= _GP(game).numinvitems))
 					quit("!Display: invalid inv item specified in @IN@");
 				snprintf(tval, sizeof(tval), "%d", playerchar->inv[inx]);
 			} else {
@@ -1897,9 +1895,9 @@ void replace_tokens(const char *srcmes, char *destm, int maxlen) {
 }
 
 const char *get_global_message(int msnum) {
-	if (game.messages[msnum - 500] == nullptr)
+	if (_GP(game).messages[msnum - 500] == nullptr)
 		return "";
-	return get_translation(game.messages[msnum - 500]);
+	return get_translation(_GP(game).messages[msnum - 500]);
 }
 
 void get_message_text(int msnum, char *buffer, char giveErr) {
@@ -1909,14 +1907,14 @@ void get_message_text(int msnum, char *buffer, char giveErr) {
 
 	if (msnum >= 500) {
 
-		if ((msnum >= MAXGLOBALMES + 500) || (game.messages[msnum - 500] == nullptr)) {
+		if ((msnum >= MAXGLOBALMES + 500) || (_GP(game).messages[msnum - 500] == nullptr)) {
 			if (giveErr)
 				quit("!DisplayGlobalMessage: message does not exist");
 			buffer[0] = 0;
 			return;
 		}
 		buffer[0] = 0;
-		replace_tokens(get_translation(game.messages[msnum - 500]), buffer, maxlen);
+		replace_tokens(get_translation(_GP(game).messages[msnum - 500]), buffer, maxlen);
 		return;
 	} else if (msnum < 0 || (size_t)msnum >= thisroom.MessageCount) {
 		if (giveErr)
@@ -2177,7 +2175,7 @@ RuntimeScriptValue Sc_Game_GetViewCount(const RuntimeScriptValue *params, int32_
 }
 
 RuntimeScriptValue Sc_Game_GetAudioClipCount(const RuntimeScriptValue *params, int32_t param_count) {
-	API_VARGET_INT(game.audioClips.size());
+	API_VARGET_INT(_GP(game).audioClips.size());
 }
 
 RuntimeScriptValue Sc_Game_GetAudioClip(const RuntimeScriptValue *params, int32_t param_count) {
diff --git a/engines/ags/engine/ac/gamestate.cpp b/engines/ags/engine/ac/gamestate.cpp
index 3d89843686..455b515fc9 100644
--- a/engines/ags/engine/ac/gamestate.cpp
+++ b/engines/ags/engine/ac/gamestate.cpp
@@ -38,13 +38,13 @@
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/shared/util/alignedstream.h"
 #include "ags/shared/util/string_utils.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
 extern RoomStruct thisroom;
 extern CharacterInfo *playerchar;
 extern ScriptSystem scsystem;
@@ -203,13 +203,13 @@ VpPoint GameState::ScreenToRoomImpl(int scrx, int scry, int view_index, bool cli
 }
 
 VpPoint GameState::ScreenToRoom(int scrx, int scry) {
-	if (game.options[OPT_BASESCRIPTAPI] >= kScriptAPI_v3507)
+	if (_GP(game).options[OPT_BASESCRIPTAPI] >= kScriptAPI_v3507)
 		return ScreenToRoomImpl(scrx, scry, -1, true, false);
 	return ScreenToRoomImpl(scrx, scry, 0, false, false);
 }
 
 VpPoint GameState::ScreenToRoomDivDown(int scrx, int scry) {
-	if (game.options[OPT_BASESCRIPTAPI] >= kScriptAPI_v3507)
+	if (_GP(game).options[OPT_BASESCRIPTAPI] >= kScriptAPI_v3507)
 		return ScreenToRoomImpl(scrx, scry, -1, true, true);
 	return ScreenToRoomImpl(scrx, scry, 0, false, true);
 }
@@ -462,7 +462,7 @@ void GameState::ReadFromSavegame(Shared::Stream *in, GameStateSvgVersion svg_ver
 	dialog_options_highlight_color = in->ReadInt32();
 	if (old_save)
 		in->ReadArrayOfInt32(reserved, GAME_STATE_RESERVED_INTS);
-	// ** up to here is referenced in the script "game." object
+	// ** up to here is referenced in the script "_GP(game)." object
 	if (old_save) {
 		in->ReadInt32(); // recording
 		in->ReadInt32(); // playback
@@ -678,7 +678,7 @@ void GameState::WriteForSavegame(Shared::Stream *out) const {
 	out->WriteInt32(speech_portrait_y);
 	out->WriteInt32(speech_display_post_time_ms);
 	out->WriteInt32(dialog_options_highlight_color);
-	// ** up to here is referenced in the script "game." object
+	// ** up to here is referenced in the script "_GP(game)." object
 	out->WriteInt32(randseed);    // random seed
 	out->WriteInt32(player_on_region);     // player's current region
 	out->WriteInt32(check_interaction_only);
@@ -813,9 +813,9 @@ void GameState::ReadCustomProperties_v340(Shared::Stream *in) {
 		// because we do not keep defaults in the saved game, and also in case
 		// this save is made by an older game version which had different
 		// properties.
-		for (int i = 0; i < game.numcharacters; ++i)
+		for (int i = 0; i < _GP(game).numcharacters; ++i)
 			Properties::ReadValues(charProps[i], in);
-		for (int i = 0; i < game.numinvitems; ++i)
+		for (int i = 0; i < _GP(game).numinvitems; ++i)
 			Properties::ReadValues(invProps[i], in);
 	}
 }
@@ -825,9 +825,9 @@ void GameState::WriteCustomProperties_v340(Shared::Stream *out) const {
 		// We temporarily remove properties that kept default values
 		// just for the saving data time to avoid getting lots of
 		// redundant data into saved games
-		for (int i = 0; i < game.numcharacters; ++i)
+		for (int i = 0; i < _GP(game).numcharacters; ++i)
 			Properties::WriteValues(charProps[i], out);
-		for (int i = 0; i < game.numinvitems; ++i)
+		for (int i = 0; i < _GP(game).numinvitems; ++i)
 			Properties::WriteValues(invProps[i], out);
 	}
 }
@@ -849,7 +849,7 @@ HorAlignment ConvertLegacyScriptAlignment(LegacyScriptAlignment align) {
 // current Script API level. This is made to make it possible to change
 // Alignment constants in the Script API and still support old version.
 HorAlignment ReadScriptAlignment(int32_t align) {
-	return game.options[OPT_BASESCRIPTAPI] < kScriptAPI_v350 ?
+	return _GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v350 ?
 		ConvertLegacyScriptAlignment((LegacyScriptAlignment)align) :
 		(HorAlignment)align;
 }
diff --git a/engines/ags/engine/ac/gamestate.h b/engines/ags/engine/ac/gamestate.h
index 486dd2423e..e3bce8a22b 100644
--- a/engines/ags/engine/ac/gamestate.h
+++ b/engines/ags/engine/ac/gamestate.h
@@ -148,7 +148,7 @@ struct GameState {
 	// no speech animation is supposed to be played at this time
 	int  dialog_options_highlight_color; // The colour used for highlighted (hovered over) text in dialog options
 	int32_t reserved[GAME_STATE_RESERVED_INTS];  // make sure if a future version adds a var, it doesn't mess anything up
-	// ** up to here is referenced in the script "game." object
+	// ** up to here is referenced in the script "_GP(game)." object
 	long  randseed;    // random seed
 	int   player_on_region;    // player's current region
 	int   screen_is_faded_out; // the screen is currently black
diff --git a/engines/ags/engine/ac/global_audio.cpp b/engines/ags/engine/ac/global_audio.cpp
index 41629df09a..a1c97b28c0 100644
--- a/engines/ags/engine/ac/global_audio.cpp
+++ b/engines/ags/engine/ac/global_audio.cpp
@@ -35,6 +35,7 @@
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/ac/timer.h"
 #include "ags/shared/util/string_compat.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -42,7 +43,7 @@ using namespace AGS::Shared;
 
 extern GameSetup usetup;
 extern GameState play;
-extern GameSetupStruct game;
+
 extern RoomStruct thisroom;
 extern SpeechLipSyncLine *splipsync;
 extern int numLipLines, curLipLine, curLipLinePhoneme;
@@ -65,7 +66,7 @@ void PlayAmbientSound(int channel, int sndnum, int vol, int x, int y) {
 	if ((vol < 1) || (vol > 255))
 		quit("!PlayAmbientSound: volume must be 1 to 255");
 
-	ScriptAudioClip *aclip = GetAudioClipForOldStyleNumber(game, false, sndnum);
+	ScriptAudioClip *aclip = GetAudioClipForOldStyleNumber(_GP(game), false, sndnum);
 	if (aclip && !is_audiotype_allowed_to_play((AudioFileType)aclip->fileType))
 		return;
 
@@ -132,7 +133,7 @@ int PlaySoundEx(int val1, int channel) {
 	if (debug_flags & DBG_NOSFX)
 		return -1;
 
-	ScriptAudioClip *aclip = GetAudioClipForOldStyleNumber(game, false, val1);
+	ScriptAudioClip *aclip = GetAudioClipForOldStyleNumber(_GP(game), false, val1);
 	if (aclip && !is_audiotype_allowed_to_play((AudioFileType)aclip->fileType))
 		return -1; // if sound is off, ignore it
 
@@ -517,10 +518,10 @@ String get_cue_filename(int charid, int sndid) {
 	String script_name;
 	if (charid >= 0) {
 		// append the first 4 characters of the script name to the filename
-		if (game.chars[charid].scrname[0] == 'c')
-			script_name.SetString(&game.chars[charid].scrname[1], 4);
+		if (_GP(game).chars[charid].scrname[0] == 'c')
+			script_name.SetString(&_GP(game).chars[charid].scrname[1], 4);
 		else
-			script_name.SetString(game.chars[charid].scrname, 4);
+			script_name.SetString(_GP(game).chars[charid].scrname, 4);
 	} else {
 		script_name = "NARR";
 	}
@@ -618,12 +619,12 @@ bool play_voice_speech(int charid, int sndid) {
 	// if the lip-sync is being used for voice sync, disable
 	// the text-related lipsync
 	if (numLipLines > 0)
-		game.options[OPT_LIPSYNCTEXT] = 0;
+		_GP(game).options[OPT_LIPSYNCTEXT] = 0;
 
 	// change Sierra w/bgrnd  to Sierra without background when voice
 	// is available (for Tierra)
-	if ((game.options[OPT_SPEECHTYPE] == 2) && (play.no_textbg_when_voice > 0)) {
-		game.options[OPT_SPEECHTYPE] = 1;
+	if ((_GP(game).options[OPT_SPEECHTYPE] == 2) && (play.no_textbg_when_voice > 0)) {
+		_GP(game).options[OPT_SPEECHTYPE] = 1;
 		play.no_textbg_when_voice = 2;
 	}
 	return true;
@@ -652,7 +653,7 @@ void stop_voice_speech() {
 	// Set back to Sierra w/bgrnd
 	if (play.no_textbg_when_voice == 2) {
 		play.no_textbg_when_voice = 1;
-		game.options[OPT_SPEECHTYPE] = 2;
+		_GP(game).options[OPT_SPEECHTYPE] = 2;
 	}
 	play.speech_has_voice = false;
 	play.speech_voice_blocking = false;
diff --git a/engines/ags/engine/ac/global_button.cpp b/engines/ags/engine/ac/global_button.cpp
index db72fbebb2..f5e25f65c1 100644
--- a/engines/ags/engine/ac/global_button.cpp
+++ b/engines/ags/engine/ac/global_button.cpp
@@ -27,16 +27,15 @@
 #include "ags/engine/ac/string.h"
 #include "ags/shared/gui/guimain.h"
 #include "ags/shared/gui/guibutton.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
-
 void SetButtonText(int guin, int objn, const char *newtx) {
 	VALIDATE_STRING(newtx);
-	if ((guin < 0) | (guin >= game.numgui))
+	if ((guin < 0) | (guin >= _GP(game).numgui))
 		quit("!SetButtonText: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount()))
 		quit("!SetButtonText: invalid object number");
@@ -49,7 +48,7 @@ void SetButtonText(int guin, int objn, const char *newtx) {
 
 
 void AnimateButton(int guin, int objn, int view, int loop, int speed, int repeat) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!AnimateButton: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!AnimateButton: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!AnimateButton: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUIButton)
 		quit("!AnimateButton: specified control is not a button");
@@ -59,7 +58,7 @@ void AnimateButton(int guin, int objn, int view, int loop, int speed, int repeat
 
 
 int GetButtonPic(int guin, int objn, int ptype) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!GetButtonPic: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!GetButtonPic: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!GetButtonPic: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUIButton)
 		quit("!GetButtonPic: specified control is not a button");
@@ -84,7 +83,7 @@ int GetButtonPic(int guin, int objn, int ptype) {
 }
 
 void SetButtonPic(int guin, int objn, int ptype, int slotn) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!SetButtonPic: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!SetButtonPic: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!SetButtonPic: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUIButton)
 		quit("!SetButtonPic: specified control is not a button");
diff --git a/engines/ags/engine/ac/global_character.cpp b/engines/ags/engine/ac/global_character.cpp
index 99e40fd043..3c938a7c9e 100644
--- a/engines/ags/engine/ac/global_character.cpp
+++ b/engines/ags/engine/ac/global_character.cpp
@@ -46,13 +46,14 @@
 #include "ags/shared/game/roomstruct.h"
 #include "ags/engine/main/game_run.h"
 #include "ags/engine/script/script.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
 
-extern GameSetupStruct game;
+
 extern ViewStruct *views;
 extern RoomObject *objs;
 extern RoomStruct thisroom;
@@ -69,28 +70,28 @@ extern CharacterInfo *playerchar;
 
 void StopMoving(int chaa) {
 
-	Character_StopMoving(&game.chars[chaa]);
+	Character_StopMoving(&_GP(game).chars[chaa]);
 }
 
 void ReleaseCharacterView(int chat) {
 	if (!is_valid_character(chat))
 		quit("!ReleaseCahracterView: invalid character supplied");
 
-	Character_UnlockView(&game.chars[chat]);
+	Character_UnlockView(&_GP(game).chars[chat]);
 }
 
 void MoveToWalkableArea(int charid) {
 	if (!is_valid_character(charid))
 		quit("!MoveToWalkableArea: invalid character specified");
 
-	Character_PlaceOnWalkableArea(&game.chars[charid]);
+	Character_PlaceOnWalkableArea(&_GP(game).chars[charid]);
 }
 
 void FaceLocation(int cha, int xx, int yy) {
 	if (!is_valid_character(cha))
 		quit("!FaceLocation: Invalid character specified");
 
-	Character_FaceLocation(&game.chars[cha], xx, yy, BLOCKING);
+	Character_FaceLocation(&_GP(game).chars[cha], xx, yy, BLOCKING);
 }
 
 void FaceCharacter(int cha, int toface) {
@@ -99,7 +100,7 @@ void FaceCharacter(int cha, int toface) {
 	if (!is_valid_character(toface))
 		quit("!FaceCharacter: invalid character specified");
 
-	Character_FaceCharacter(&game.chars[cha], &game.chars[toface], BLOCKING);
+	Character_FaceCharacter(&_GP(game).chars[cha], &_GP(game).chars[toface], BLOCKING);
 }
 
 
@@ -107,13 +108,13 @@ void SetCharacterIdle(int who, int iview, int itime) {
 	if (!is_valid_character(who))
 		quit("!SetCharacterIdle: Invalid character specified");
 
-	Character_SetIdleView(&game.chars[who], iview, itime);
+	Character_SetIdleView(&_GP(game).chars[who], iview, itime);
 }
 
 
 
 int GetCharacterWidth(int ww) {
-	CharacterInfo *char1 = &game.chars[ww];
+	CharacterInfo *char1 = &_GP(game).chars[ww];
 
 	if (charextra[ww].width < 1) {
 		if ((char1->view < 0) ||
@@ -123,13 +124,13 @@ int GetCharacterWidth(int ww) {
 			return data_to_game_coord(4);
 		}
 
-		return game.SpriteInfos[views[char1->view].loops[char1->loop].frames[char1->frame].pic].Width;
+		return _GP(game).SpriteInfos[views[char1->view].loops[char1->loop].frames[char1->frame].pic].Width;
 	} else
 		return charextra[ww].width;
 }
 
 int GetCharacterHeight(int charid) {
-	CharacterInfo *char1 = &game.chars[charid];
+	CharacterInfo *char1 = &_GP(game).chars[charid];
 
 	if (charextra[charid].height < 1) {
 		if ((char1->view < 0) ||
@@ -139,7 +140,7 @@ int GetCharacterHeight(int charid) {
 			return data_to_game_coord(2);
 		}
 
-		return game.SpriteInfos[views[char1->view].loops[char1->loop].frames[char1->frame].pic].Height;
+		return _GP(game).SpriteInfos[views[char1->view].loops[char1->loop].frames[char1->frame].pic].Height;
 	} else
 		return charextra[charid].height;
 }
@@ -149,7 +150,7 @@ int GetCharacterHeight(int charid) {
 void SetCharacterBaseline(int obn, int basel) {
 	if (!is_valid_character(obn)) quit("!SetCharacterBaseline: invalid object number specified");
 
-	Character_SetBaseline(&game.chars[obn], basel);
+	Character_SetBaseline(&_GP(game).chars[obn], basel);
 }
 
 // pass trans=0 for fully solid, trans=100 for fully transparent
@@ -157,14 +158,14 @@ void SetCharacterTransparency(int obn, int trans) {
 	if (!is_valid_character(obn))
 		quit("!SetCharTransparent: invalid character number specified");
 
-	Character_SetTransparency(&game.chars[obn], trans);
+	Character_SetTransparency(&_GP(game).chars[obn], trans);
 }
 
 void scAnimateCharacter(int chh, int loopn, int sppd, int rept) {
 	if (!is_valid_character(chh))
 		quit("AnimateCharacter: invalid character");
 
-	animate_character(&game.chars[chh], loopn, sppd, rept);
+	animate_character(&_GP(game).chars[chh], loopn, sppd, rept);
 }
 
 void AnimateCharacterEx(int chh, int loopn, int sppd, int rept, int direction, int blocking) {
@@ -183,7 +184,7 @@ void AnimateCharacterEx(int chh, int loopn, int sppd, int rept, int direction, i
 	else
 		blocking = IN_BACKGROUND;
 
-	Character_Animate(&game.chars[chh], loopn, sppd, rept, blocking, direction);
+	Character_Animate(&_GP(game).chars[chh], loopn, sppd, rept, blocking, direction);
 
 }
 
@@ -192,7 +193,7 @@ void SetPlayerCharacter(int newchar) {
 	if (!is_valid_character(newchar))
 		quit("!SetPlayerCharacter: Invalid character specified");
 
-	Character_SetAsPlayer(&game.chars[newchar]);
+	Character_SetAsPlayer(&_GP(game).chars[newchar]);
 }
 
 void FollowCharacterEx(int who, int tofollow, int distaway, int eagerness) {
@@ -203,10 +204,10 @@ void FollowCharacterEx(int who, int tofollow, int distaway, int eagerness) {
 		if (!is_valid_character(tofollow))
 			quit("!FollowCharacterEx: invalid character to follow");
 		else
-			chtofollow = &game.chars[tofollow];
+			chtofollow = &_GP(game).chars[tofollow];
 	}
 
-	Character_FollowCharacter(&game.chars[who], chtofollow, distaway, eagerness);
+	Character_FollowCharacter(&_GP(game).chars[who], chtofollow, distaway, eagerness);
 }
 
 void FollowCharacter(int who, int tofollow) {
@@ -217,7 +218,7 @@ void SetCharacterIgnoreLight(int who, int yesorno) {
 	if (!is_valid_character(who))
 		quit("!SetCharacterIgnoreLight: Invalid character specified");
 
-	Character_SetIgnoreLighting(&game.chars[who], yesorno);
+	Character_SetIgnoreLighting(&_GP(game).chars[who], yesorno);
 }
 
 
@@ -233,7 +234,7 @@ void MoveCharacterStraight(int cc, int xx, int yy) {
 	if (!is_valid_character(cc))
 		quit("!MoveCharacterStraight: invalid character specified");
 
-	Character_WalkStraight(&game.chars[cc], xx, yy, IN_BACKGROUND);
+	Character_WalkStraight(&_GP(game).chars[cc], xx, yy, IN_BACKGROUND);
 }
 
 // Append to character path
@@ -241,19 +242,19 @@ void MoveCharacterPath(int chac, int tox, int toy) {
 	if (!is_valid_character(chac))
 		quit("!MoveCharacterPath: invalid character specified");
 
-	Character_AddWaypoint(&game.chars[chac], tox, toy);
+	Character_AddWaypoint(&_GP(game).chars[chac], tox, toy);
 }
 
 
 int GetPlayerCharacter() {
-	return game.playercharacter;
+	return _GP(game).playercharacter;
 }
 
 void SetCharacterSpeedEx(int chaa, int xspeed, int yspeed) {
 	if (!is_valid_character(chaa))
 		quit("!SetCharacterSpeedEx: invalid character");
 
-	Character_SetSpeed(&game.chars[chaa], xspeed, yspeed);
+	Character_SetSpeed(&_GP(game).chars[chaa], xspeed, yspeed);
 
 }
 
@@ -264,45 +265,45 @@ void SetCharacterSpeed(int chaa, int nspeed) {
 void SetTalkingColor(int chaa, int ncol) {
 	if (!is_valid_character(chaa)) quit("!SetTalkingColor: invalid character");
 
-	Character_SetSpeechColor(&game.chars[chaa], ncol);
+	Character_SetSpeechColor(&_GP(game).chars[chaa], ncol);
 }
 
 void SetCharacterSpeechView(int chaa, int vii) {
 	if (!is_valid_character(chaa))
 		quit("!SetCharacterSpeechView: invalid character specified");
 
-	Character_SetSpeechView(&game.chars[chaa], vii);
+	Character_SetSpeechView(&_GP(game).chars[chaa], vii);
 }
 
 void SetCharacterBlinkView(int chaa, int vii, int intrv) {
 	if (!is_valid_character(chaa))
 		quit("!SetCharacterBlinkView: invalid character specified");
 
-	Character_SetBlinkView(&game.chars[chaa], vii);
-	Character_SetBlinkInterval(&game.chars[chaa], intrv);
+	Character_SetBlinkView(&_GP(game).chars[chaa], vii);
+	Character_SetBlinkInterval(&_GP(game).chars[chaa], intrv);
 }
 
 void SetCharacterView(int chaa, int vii) {
 	if (!is_valid_character(chaa))
 		quit("!SetCharacterView: invalid character specified");
 
-	Character_LockView(&game.chars[chaa], vii);
+	Character_LockView(&_GP(game).chars[chaa], vii);
 }
 
 void SetCharacterFrame(int chaa, int view, int loop, int frame) {
 
-	Character_LockViewFrame(&game.chars[chaa], view, loop, frame);
+	Character_LockViewFrame(&_GP(game).chars[chaa], view, loop, frame);
 }
 
 // similar to SetCharView, but aligns the frame to make it line up
 void SetCharacterViewEx(int chaa, int vii, int loop, int align) {
 
-	Character_LockViewAligned(&game.chars[chaa], vii, loop, align);
+	Character_LockViewAligned(&_GP(game).chars[chaa], vii, loop, align);
 }
 
 void SetCharacterViewOffset(int chaa, int vii, int xoffs, int yoffs) {
 
-	Character_LockViewOffset(&game.chars[chaa], vii, xoffs, yoffs);
+	Character_LockViewOffset(&_GP(game).chars[chaa], vii, xoffs, yoffs);
 }
 
 
@@ -310,24 +311,24 @@ void ChangeCharacterView(int chaa, int vii) {
 	if (!is_valid_character(chaa))
 		quit("!ChangeCharacterView: invalid character specified");
 
-	Character_ChangeView(&game.chars[chaa], vii);
+	Character_ChangeView(&_GP(game).chars[chaa], vii);
 }
 
 void SetCharacterClickable(int cha, int clik) {
 	if (!is_valid_character(cha))
 		quit("!SetCharacterClickable: Invalid character specified");
 	// make the character clicklabe (reset "No interaction" bit)
-	game.chars[cha].flags &= ~CHF_NOINTERACT;
+	_GP(game).chars[cha].flags &= ~CHF_NOINTERACT;
 	// if they don't want it clickable, set the relevant bit
 	if (clik == 0)
-		game.chars[cha].flags |= CHF_NOINTERACT;
+		_GP(game).chars[cha].flags |= CHF_NOINTERACT;
 }
 
 void SetCharacterIgnoreWalkbehinds(int cha, int clik) {
 	if (!is_valid_character(cha))
 		quit("!SetCharacterIgnoreWalkbehinds: Invalid character specified");
 
-	Character_SetIgnoreWalkbehinds(&game.chars[cha], clik);
+	Character_SetIgnoreWalkbehinds(&_GP(game).chars[cha], clik);
 }
 
 
@@ -339,7 +340,7 @@ void MoveCharacterToObject(int chaa, int obbj) {
 
 	walk_character(chaa, objs[obbj].x + 5, objs[obbj].y + 6, 0, true);
 
-	GameLoopUntilNotMoving(&game.chars[chaa].walking);
+	GameLoopUntilNotMoving(&_GP(game).chars[chaa].walking);
 }
 
 void MoveCharacterToHotspot(int chaa, int hotsp) {
@@ -348,7 +349,7 @@ void MoveCharacterToHotspot(int chaa, int hotsp) {
 	if (thisroom.Hotspots[hotsp].WalkTo.X < 1) return;
 	walk_character(chaa, thisroom.Hotspots[hotsp].WalkTo.X, thisroom.Hotspots[hotsp].WalkTo.Y, 0, true);
 
-	GameLoopUntilNotMoving(&game.chars[chaa].walking);
+	GameLoopUntilNotMoving(&_GP(game).chars[chaa].walking);
 }
 
 void MoveCharacterBlocking(int chaa, int xx, int yy, int direct) {
@@ -357,7 +358,7 @@ void MoveCharacterBlocking(int chaa, int xx, int yy, int direct) {
 
 	// check if they try to move the player when Hide Player Char is
 	// ticked -- otherwise this will hang the game
-	if (game.chars[chaa].on != 1) {
+	if (_GP(game).chars[chaa].on != 1) {
 		debug_script_warn("MoveCharacterBlocking: character is turned off (is Hide Player Character selected?) and cannot be moved");
 		return;
 	}
@@ -367,15 +368,15 @@ void MoveCharacterBlocking(int chaa, int xx, int yy, int direct) {
 	else
 		MoveCharacter(chaa, xx, yy);
 
-	GameLoopUntilNotMoving(&game.chars[chaa].walking);
+	GameLoopUntilNotMoving(&_GP(game).chars[chaa].walking);
 }
 
 int GetCharacterSpeechAnimationDelay(CharacterInfo *cha) {
-	if ((loaded_game_file_version < kGameVersion_312) && (game.options[OPT_SPEECHTYPE] != 0)) {
+	if ((loaded_game_file_version < kGameVersion_312) && (_GP(game).options[OPT_SPEECHTYPE] != 0)) {
 		// legacy versions of AGS assigned a fixed delay to Sierra-style speech only
 		return 5;
 	}
-	if (game.options[OPT_GLOBALTALKANIMSPD] != 0)
+	if (_GP(game).options[OPT_GLOBALTALKANIMSPD] != 0)
 		return play.talkanim_speed;
 	else
 		return cha->speech_anim_speed;
@@ -401,12 +402,12 @@ void RunCharacterInteraction(int cc, int mood) {
 	evblocknum = cc;
 	if (loaded_game_file_version > kGameVersion_272) {
 		if (passon >= 0)
-			run_interaction_script(game.charScripts[cc].get(), passon, 4, (passon == 3));
-		run_interaction_script(game.charScripts[cc].get(), 4);  // any click on char
+			run_interaction_script(_GP(game).charScripts[cc].get(), passon, 4, (passon == 3));
+		run_interaction_script(_GP(game).charScripts[cc].get(), 4);  // any click on char
 	} else {
 		if (passon >= 0)
-			run_interaction_event(game.intrChar[cc].get(), passon, 4, (passon == 3));
-		run_interaction_event(game.intrChar[cc].get(), 4); // any click on char
+			run_interaction_event(_GP(game).intrChar[cc].get(), passon, 4, (passon == 3));
+		run_interaction_event(_GP(game).intrChar[cc].get(), 4); // any click on char
 	}
 }
 
@@ -416,7 +417,7 @@ int AreCharObjColliding(int charid, int objid) {
 	if (!is_valid_object(objid))
 		quit("!AreCharObjColliding: invalid object number");
 
-	return Character_IsCollidingWithObject(&game.chars[charid], &scrObj[objid]);
+	return Character_IsCollidingWithObject(&_GP(game).chars[charid], &scrObj[objid]);
 }
 
 int AreCharactersColliding(int cchar1, int cchar2) {
@@ -425,24 +426,24 @@ int AreCharactersColliding(int cchar1, int cchar2) {
 	if (!is_valid_character(cchar2))
 		quit("!AreCharactersColliding: invalid char2");
 
-	return Character_IsCollidingWithChar(&game.chars[cchar1], &game.chars[cchar2]);
+	return Character_IsCollidingWithChar(&_GP(game).chars[cchar1], &_GP(game).chars[cchar2]);
 }
 
 int GetCharacterProperty(int cha, const char *property) {
 	if (!is_valid_character(cha))
 		quit("!GetCharacterProperty: invalid character");
-	return get_int_property(game.charProps[cha], play.charProps[cha], property);
+	return get_int_property(_GP(game).charProps[cha], play.charProps[cha], property);
 }
 
 void SetCharacterProperty(int who, int flag, int yesorno) {
 	if (!is_valid_character(who))
 		quit("!SetCharacterProperty: Invalid character specified");
 
-	Character_SetOption(&game.chars[who], flag, yesorno);
+	Character_SetOption(&_GP(game).chars[who], flag, yesorno);
 }
 
 void GetCharacterPropertyText(int item, const char *property, char *bufer) {
-	get_text_property(game.charProps[item], play.charProps[item], property, bufer);
+	get_text_property(_GP(game).charProps[item], play.charProps[item], property, bufer);
 }
 
 int GetCharIDAtScreen(int xx, int yy) {
@@ -455,7 +456,7 @@ int GetCharIDAtScreen(int xx, int yy) {
 void SetActiveInventory(int iit) {
 
 	ScriptInvItem *tosend = nullptr;
-	if ((iit > 0) && (iit < game.numinvitems))
+	if ((iit > 0) && (iit < _GP(game).numinvitems))
 		tosend = &scrInv[iit];
 	else if (iit != -1)
 		quitprintf("!SetActiveInventory: invalid inventory number %d", iit);
@@ -464,14 +465,14 @@ void SetActiveInventory(int iit) {
 }
 
 void update_invorder() {
-	for (int cc = 0; cc < game.numcharacters; cc++) {
+	for (int cc = 0; cc < _GP(game).numcharacters; cc++) {
 		charextra[cc].invorder_count = 0;
 		int ff, howmany;
 		// Iterate through all inv items, adding them once (or multiple
 		// times if requested) to the list.
-		for (ff = 0; ff < game.numinvitems; ff++) {
-			howmany = game.chars[cc].inv[ff];
-			if ((game.options[OPT_DUPLICATEINV] == 0) && (howmany > 1))
+		for (ff = 0; ff < _GP(game).numinvitems; ff++) {
+			howmany = _GP(game).chars[cc].inv[ff];
+			if ((_GP(game).options[OPT_DUPLICATEINV] == 0) && (howmany > 1))
 				howmany = 1;
 
 			for (int ts = 0; ts < howmany; ts++) {
@@ -484,7 +485,7 @@ void update_invorder() {
 		}
 	}
 	// backwards compatibility
-	play.obsolete_inv_numorder = charextra[game.playercharacter].invorder_count;
+	play.obsolete_inv_numorder = charextra[_GP(game).playercharacter].invorder_count;
 
 	guis_need_update = 1;
 }
@@ -495,7 +496,7 @@ void add_inventory(int inum) {
 
 	Character_AddInventory(playerchar, &scrInv[inum], SCR_NO_VALUE);
 
-	play.obsolete_inv_numorder = charextra[game.playercharacter].invorder_count;
+	play.obsolete_inv_numorder = charextra[_GP(game).playercharacter].invorder_count;
 }
 
 void lose_inventory(int inum) {
@@ -504,36 +505,36 @@ void lose_inventory(int inum) {
 
 	Character_LoseInventory(playerchar, &scrInv[inum]);
 
-	play.obsolete_inv_numorder = charextra[game.playercharacter].invorder_count;
+	play.obsolete_inv_numorder = charextra[_GP(game).playercharacter].invorder_count;
 }
 
 void AddInventoryToCharacter(int charid, int inum) {
 	if (!is_valid_character(charid))
 		quit("!AddInventoryToCharacter: invalid character specified");
-	if ((inum < 1) || (inum >= game.numinvitems))
+	if ((inum < 1) || (inum >= _GP(game).numinvitems))
 		quit("!AddInventory: invalid inv item specified");
 
-	Character_AddInventory(&game.chars[charid], &scrInv[inum], SCR_NO_VALUE);
+	Character_AddInventory(&_GP(game).chars[charid], &scrInv[inum], SCR_NO_VALUE);
 }
 
 void LoseInventoryFromCharacter(int charid, int inum) {
 	if (!is_valid_character(charid))
 		quit("!LoseInventoryFromCharacter: invalid character specified");
-	if ((inum < 1) || (inum >= game.numinvitems))
+	if ((inum < 1) || (inum >= _GP(game).numinvitems))
 		quit("!AddInventory: invalid inv item specified");
 
-	Character_LoseInventory(&game.chars[charid], &scrInv[inum]);
+	Character_LoseInventory(&_GP(game).chars[charid], &scrInv[inum]);
 }
 
 void DisplayThought(int chid, const char *text) {
-	if ((chid < 0) || (chid >= game.numcharacters))
+	if ((chid < 0) || (chid >= _GP(game).numcharacters))
 		quit("!DisplayThought: invalid character specified");
 
 	_DisplayThoughtCore(chid, text);
 }
 
 void __sc_displayspeech(int chid, const char *text) {
-	if ((chid < 0) || (chid >= game.numcharacters))
+	if ((chid < 0) || (chid >= _GP(game).numcharacters))
 		quit("!DisplaySpeech: invalid character specified");
 
 	_DisplaySpeechCore(chid, text);
@@ -557,7 +558,7 @@ int DisplaySpeechBackground(int charid, const char *speel) {
 	}
 
 	int ovrl = CreateTextOverlay(OVR_AUTOPLACE, charid, play.GetUIViewport().GetWidth() / 2, FONT_SPEECH,
-		-game.chars[charid].talkcolor, get_translation(speel), DISPLAYTEXT_NORMALOVERLAY);
+		-_GP(game).chars[charid].talkcolor, get_translation(speel), DISPLAYTEXT_NORMALOVERLAY);
 
 	int scid = find_overlay_of_type(ovrl);
 	screenover[scid].bgSpeechForChar = charid;
diff --git a/engines/ags/engine/ac/global_debug.cpp b/engines/ags/engine/ac/global_debug.cpp
index b92209ad87..6b5acf38e7 100644
--- a/engines/ags/engine/ac/global_debug.cpp
+++ b/engines/ags/engine/ac/global_debug.cpp
@@ -46,14 +46,14 @@
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/engine/main/graphics_mode.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern GameSetup usetup;
 extern GameState play;
 extern RoomStruct thisroom;
@@ -61,7 +61,7 @@ extern CharacterInfo *playerchar;
 
 extern int convert_16bit_bgr;
 extern IGraphicsDriver *gfxDriver;
-extern SpriteCache spriteset;
+
 extern TreeMap *transtree;
 extern int displayed_room, starting_room;
 extern MoveList *mls;
@@ -76,12 +76,12 @@ String GetRuntimeInfo() {
 		"[Game resolution %d x %d (%d-bit)"
 		"[Running %d x %d at %d-bit%s%s[GFX: %s; %s[Draw frame %d x %d["
 		"Sprite cache size: %d KB (limit %d KB; %d locked)",
-		_G(EngineVersion).LongString.GetCStr(), game.GetGameRes().Width, game.GetGameRes().Height, game.GetColorDepth(),
+		_G(EngineVersion).LongString.GetCStr(), _GP(game).GetGameRes().Width, _GP(game).GetGameRes().Height, _GP(game).GetColorDepth(),
 		mode.Width, mode.Height, mode.ColorDepth, (convert_16bit_bgr) ? " BGR" : "",
 		mode.Windowed ? " W" : "",
 		gfxDriver->GetDriverName(), filter->GetInfo().Name.GetCStr(),
 		render_frame.GetWidth(), render_frame.GetHeight(),
-		spriteset.GetCacheSize() / 1024, spriteset.GetMaxCacheSize() / 1024, spriteset.GetLockedSize() / 1024);
+		_GP(spriteset).GetCacheSize() / 1024, _GP(spriteset).GetMaxCacheSize() / 1024, _GP(spriteset).GetLockedSize() / 1024);
 	if (play.separate_music_lib)
 		runtimeInfo.Append("[AUDIO.VOX enabled");
 	if (play.want_speech >= 1)
@@ -98,7 +98,7 @@ void script_debug(int cmdd, int dataa) {
 	if (play.debug_mode == 0) return;
 	int rr;
 	if (cmdd == 0) {
-		for (rr = 1; rr < game.numinvitems; rr++)
+		for (rr = 1; rr < _GP(game).numinvitems; rr++)
 			playerchar->inv[rr] = 1;
 		update_invorder();
 		//    Display("invorder decided there are %d items[display %d",play.inv_numorder,play.inv_numdisp);
@@ -107,7 +107,7 @@ void script_debug(int cmdd, int dataa) {
 		Display(toDisplay.GetCStr());
 		//    Display("shftR: %d  shftG: %d  shftB: %d", _rgb_r_shift_16, _rgb_g_shift_16, _rgb_b_shift_16);
 		//    Display("Remaining memory: %d kb",_go32_dpmi_remaining_virtual_memory()/1024);
-		//Display("Play char bcd: %d",->GetColorDepth(spriteset[views[playerchar->view].frames[playerchar->loop][playerchar->frame].pic]));
+		//Display("Play char bcd: %d",->GetColorDepth(_GP(spriteset)[views[playerchar->view].frames[playerchar->loop][playerchar->frame].pic]));
 	} else if (cmdd == 2) {
 		// show walkable areas from here
 		// TODO: support multiple viewports?!
@@ -131,7 +131,7 @@ void script_debug(int cmdd, int dataa) {
 		invalidate_screen();
 	} else if (cmdd == 3) {
 		int goToRoom = -1;
-		if (game.roomCount == 0) {
+		if (_GP(game).roomCount == 0) {
 			char inroomtex[80];
 			sprintf(inroomtex, "!Enter new room: (in room %d)", displayed_room);
 			setup_for_dialog();
@@ -139,7 +139,7 @@ void script_debug(int cmdd, int dataa) {
 			restore_after_dialog();
 		} else {
 			setup_for_dialog();
-			goToRoom = roomSelectorWindow(displayed_room, game.roomCount, game.roomNumbers, game.roomNames);
+			goToRoom = roomSelectorWindow(displayed_room, _GP(game).roomCount, _GP(game).roomNumbers, _GP(game).roomNames);
 			restore_after_dialog();
 		}
 		if (goToRoom >= 0)
@@ -148,14 +148,14 @@ void script_debug(int cmdd, int dataa) {
 		if (display_fps != kFPS_Forced)
 			display_fps = (FPSDisplayMode)dataa;
 	} else if (cmdd == 5) {
-		if (dataa == 0) dataa = game.playercharacter;
-		if (game.chars[dataa].walking < 1) {
+		if (dataa == 0) dataa = _GP(game).playercharacter;
+		if (_GP(game).chars[dataa].walking < 1) {
 			Display("Not currently moving.");
 			return;
 		}
 		Bitmap *tempw = BitmapHelper::CreateTransparentBitmap(thisroom.WalkAreaMask->GetWidth(), thisroom.WalkAreaMask->GetHeight());
-		int mlsnum = game.chars[dataa].walking;
-		if (game.chars[dataa].walking >= TURNING_AROUND)
+		int mlsnum = _GP(game).chars[dataa].walking;
+		if (_GP(game).chars[dataa].walking >= TURNING_AROUND)
 			mlsnum %= TURNING_AROUND;
 		MoveList *cmls = &mls[mlsnum];
 		for (int i = 0; i < cmls->numstage - 1; i++) {
diff --git a/engines/ags/engine/ac/global_dialog.cpp b/engines/ags/engine/ac/global_dialog.cpp
index 82f46aa948..1eb6a7b8d9 100644
--- a/engines/ags/engine/ac/global_dialog.cpp
+++ b/engines/ags/engine/ac/global_dialog.cpp
@@ -30,18 +30,18 @@
 #include "ags/engine/debugging/debugger.h"
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
 extern GameState play;
 extern DialogTopic *dialog;
 
 ScriptPosition last_in_dialog_request_script_pos;
 void RunDialog(int tum) {
-	if ((tum < 0) | (tum >= game.numdialog))
+	if ((tum < 0) | (tum >= _GP(game).numdialog))
 		quit("!RunDialog: invalid topic number specified");
 
 	can_run_delayed_command();
@@ -75,7 +75,7 @@ void StopDialog() {
 }
 
 void SetDialogOption(int dlg, int opt, int onoroff, bool dlg_script) {
-	if ((dlg < 0) | (dlg >= game.numdialog))
+	if ((dlg < 0) | (dlg >= _GP(game).numdialog))
 		quit("!SetDialogOption: Invalid topic number specified");
 	if ((opt < 1) | (opt > dialog[dlg].numoptions)) {
 		// Pre-3.1.1 games had "dialog scripts" that were written in different language and
@@ -96,7 +96,7 @@ void SetDialogOption(int dlg, int opt, int onoroff, bool dlg_script) {
 }
 
 int GetDialogOption(int dlg, int opt) {
-	if ((dlg < 0) | (dlg >= game.numdialog))
+	if ((dlg < 0) | (dlg >= _GP(game).numdialog))
 		quit("!GetDialogOption: Invalid topic number specified");
 	if ((opt < 1) | (opt > dialog[dlg].numoptions))
 		quit("!GetDialogOption: Invalid option number specified");
diff --git a/engines/ags/engine/ac/global_display.cpp b/engines/ags/engine/ac/global_display.cpp
index 4cbacc467f..b97937cf5f 100644
--- a/engines/ags/engine/ac/global_display.cpp
+++ b/engines/ags/engine/ac/global_display.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-//include <cstdio>
-//include <stdarg.h>
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/character.h"
 #include "ags/engine/ac/display.h"
@@ -40,6 +38,7 @@
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/shared/game/roomstruct.h"
 #include "ags/engine/main/game_run.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -49,7 +48,7 @@ extern TopBarSettings topBar;
 extern GameState play;
 extern RoomStruct thisroom;
 extern int display_message_aschar;
-extern GameSetupStruct game;
+
 
 void Display(const char *texx, ...) {
 	char displbuf[STD_BUFFER_SIZE];
@@ -169,8 +168,8 @@ void DisplayAtY(int ypos, const char *texx) {
 	if (ypos > 0)
 		ypos = data_to_game_coord(ypos);
 
-	if (game.options[OPT_ALWAYSSPCH])
-		DisplaySpeechAt(-1, (ypos > 0) ? game_to_data_coord(ypos) : ypos, -1, game.playercharacter, texx);
+	if (_GP(game).options[OPT_ALWAYSSPCH])
+		DisplaySpeechAt(-1, (ypos > 0) ? game_to_data_coord(ypos) : ypos, -1, _GP(game).playercharacter, texx);
 	else {
 		// Normal "Display" in text box
 
@@ -189,7 +188,7 @@ void DisplayAtY(int ypos, const char *texx) {
 void SetSpeechStyle(int newstyle) {
 	if ((newstyle < 0) || (newstyle > 3))
 		quit("!SetSpeechStyle: must use a SPEECH_* constant as parameter");
-	game.options[OPT_SPEECHTYPE] = newstyle;
+	_GP(game).options[OPT_SPEECHTYPE] = newstyle;
 }
 
 void SetSkipSpeech(SkipSpeechStyle newval) {
diff --git a/engines/ags/engine/ac/global_drawingsurface.cpp b/engines/ags/engine/ac/global_drawingsurface.cpp
index d513678e1d..e1b571066d 100644
--- a/engines/ags/engine/ac/global_drawingsurface.cpp
+++ b/engines/ags/engine/ac/global_drawingsurface.cpp
@@ -36,6 +36,7 @@
 #include "ags/shared/ac/spritecache.h"
 #include "ags/shared/gfx/gfx_def.h"
 #include "ags/engine/gfx/gfx_util.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -45,8 +46,8 @@ using namespace AGS::Engine;
 extern Bitmap *raw_saved_screen;
 extern RoomStruct thisroom;
 extern GameState play;
-extern SpriteCache spriteset;
-extern GameSetupStruct game;
+
+
 
 // Raw screen writing routines - similar to old CapturedStuff
 #define RAW_START() play.raw_drawing_surface = thisroom.BgFrames[play.bg_frame].Graphic; play.raw_modified[play.bg_frame] = 1
@@ -175,12 +176,12 @@ void RawPrintMessageWrapped(int xx, int yy, int wid, int font, int msgm) {
 }
 
 void RawDrawImageCore(int xx, int yy, int slot, int alpha) {
-	if ((slot < 0) || (spriteset[slot] == nullptr))
+	if ((slot < 0) || (_GP(spriteset)[slot] == nullptr))
 		quit("!RawDrawImage: invalid sprite slot number specified");
 	RAW_START();
 
-	if (spriteset[slot]->GetColorDepth() != RAW_SURFACE()->GetColorDepth()) {
-		debug_script_warn("RawDrawImage: Sprite %d colour depth %d-bit not same as background depth %d-bit", slot, spriteset[slot]->GetColorDepth(), RAW_SURFACE()->GetColorDepth());
+	if (_GP(spriteset)[slot]->GetColorDepth() != RAW_SURFACE()->GetColorDepth()) {
+		debug_script_warn("RawDrawImage: Sprite %d colour depth %d-bit not same as background depth %d-bit", slot, _GP(spriteset)[slot]->GetColorDepth(), RAW_SURFACE()->GetColorDepth());
 	}
 
 	draw_sprite_slot_support_alpha(RAW_SURFACE(), false, xx, yy, slot, kBlendMode_Alpha, alpha);
@@ -233,7 +234,7 @@ void RawDrawImageTransparent(int xx, int yy, int slot, int legacy_transparency)
 	update_polled_stuff_if_runtime();  // this operation can be slow so stop music skipping
 }
 void RawDrawImageResized(int xx, int yy, int gotSlot, int width, int height) {
-	if ((gotSlot < 0) || (spriteset[gotSlot] == nullptr))
+	if ((gotSlot < 0) || (_GP(spriteset)[gotSlot] == nullptr))
 		quit("!RawDrawImageResized: invalid sprite slot number specified");
 	// very small, don't draw it
 	if ((width < 1) || (height < 1))
@@ -243,9 +244,9 @@ void RawDrawImageResized(int xx, int yy, int gotSlot, int width, int height) {
 	data_to_game_coords(&width, &height);
 
 	// resize the sprite to the requested size
-	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[gotSlot]->GetColorDepth());
-	newPic->StretchBlt(spriteset[gotSlot],
-		RectWH(0, 0, game.SpriteInfos[gotSlot].Width, game.SpriteInfos[gotSlot].Height),
+	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, _GP(spriteset)[gotSlot]->GetColorDepth());
+	newPic->StretchBlt(_GP(spriteset)[gotSlot],
+		RectWH(0, 0, _GP(game).SpriteInfos[gotSlot].Width, _GP(game).SpriteInfos[gotSlot].Height),
 		RectWH(0, 0, width, height));
 
 	RAW_START();
diff --git a/engines/ags/engine/ac/global_dynamicsprite.cpp b/engines/ags/engine/ac/global_dynamicsprite.cpp
index 59a7eb951d..b1477530d8 100644
--- a/engines/ags/engine/ac/global_dynamicsprite.cpp
+++ b/engines/ags/engine/ac/global_dynamicsprite.cpp
@@ -29,13 +29,14 @@
 #include "ags/engine/ac/runtime_defines.h" //MAX_PATH
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern SpriteCache spriteset;
+
 extern IGraphicsDriver *gfxDriver;
 
 int LoadImageFile(const char *filename) {
@@ -49,7 +50,7 @@ int LoadImageFile(const char *filename) {
 	if (!loadedFile)
 		return 0;
 
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return 0;
 
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index b2f3f19605..99dda63ba7 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -69,7 +69,7 @@
 #include "ags/engine/main/game_file.h"
 #include "ags/shared/util/string_utils.h"
 #include "ags/engine/media/audio/audio_system.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -81,12 +81,12 @@ extern GameState play;
 extern ExecutingScript *curscript;
 extern int displayed_room;
 extern int game_paused;
-extern SpriteCache spriteset;
+
 extern char gamefilenamebuf[200];
 extern GameSetup usetup;
 extern unsigned int load_new_game;
 extern int load_new_game_restore;
-extern GameSetupStruct game;
+
 extern ViewStruct *views;
 extern RoomStatus *croom;
 extern int gui_disabled_style;
@@ -185,13 +185,13 @@ int LoadSaveSlotScreenshot(int slnum, int width, int height) {
 	if (gotSlot == 0)
 		return 0;
 
-	if ((game.SpriteInfos[gotSlot].Width == width) && (game.SpriteInfos[gotSlot].Height == height))
+	if ((_GP(game).SpriteInfos[gotSlot].Width == width) && (_GP(game).SpriteInfos[gotSlot].Height == height))
 		return gotSlot;
 
 	// resize the sprite to the requested size
-	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[gotSlot]->GetColorDepth());
-	newPic->StretchBlt(spriteset[gotSlot],
-		RectWH(0, 0, game.SpriteInfos[gotSlot].Width, game.SpriteInfos[gotSlot].Height),
+	Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, _GP(spriteset)[gotSlot]->GetColorDepth());
+	newPic->StretchBlt(_GP(spriteset)[gotSlot],
+		RectWH(0, 0, _GP(game).SpriteInfos[gotSlot].Width, _GP(game).SpriteInfos[gotSlot].Height),
 		RectWH(0, 0, width, height));
 
 	update_polled_stuff_if_runtime();
@@ -287,8 +287,8 @@ int RunAGSGame(const char *newgame, unsigned int mode, int data) {
 	if (!err)
 		quitprintf("!RunAGSGame: error loading new game file:\n%s", err->FullMessage().GetCStr());
 
-	spriteset.Reset();
-	err = spriteset.InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
+	_GP(spriteset).Reset();
+	err = _GP(spriteset).InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
 	if (!err)
 		quitprintf("!RunAGSGame: error loading new sprites:\n%s", err->FullMessage().GetCStr());
 
@@ -325,7 +325,7 @@ int GetGameParameter(int parm, int data1, int data2, int data3) {
 	case GP_FRAMESOUND:
 	case GP_ISFRAMEFLIPPED:
 	{
-		if ((data1 < 1) || (data1 > game.numviews)) {
+		if ((data1 < 1) || (data1 > _GP(game).numviews)) {
 			quitprintf("!GetGameParameter: invalid view specified (v: %d, l: %d, f: %d)", data1, data2, data3);
 		}
 		if ((data2 < 0) || (data2 >= views[data1 - 1].numLoops)) {
@@ -352,13 +352,13 @@ int GetGameParameter(int parm, int data1, int data2, int data3) {
 	case GP_ISRUNNEXTLOOP:
 		return Game_GetRunNextSettingForLoop(data1, data2);
 	case GP_NUMGUIS:
-		return game.numgui;
+		return _GP(game).numgui;
 	case GP_NUMOBJECTS:
 		return croom->numobj;
 	case GP_NUMCHARACTERS:
-		return game.numcharacters;
+		return _GP(game).numcharacters;
 	case GP_NUMINVITEMS:
-		return game.numinvitems;
+		return _GP(game).numinvitems;
 	default:
 		quit("!GetGameParameter: unknown parameter specified");
 	}
@@ -402,27 +402,27 @@ int SetGameOption(int opt, int setting) {
 		quit("!SetGameOption: invalid option specified");
 
 	if (opt == OPT_ANTIGLIDE) {
-		for (int i = 0; i < game.numcharacters; i++) {
+		for (int i = 0; i < _GP(game).numcharacters; i++) {
 			if (setting)
-				game.chars[i].flags |= CHF_ANTIGLIDE;
+				_GP(game).chars[i].flags |= CHF_ANTIGLIDE;
 			else
-				game.chars[i].flags &= ~CHF_ANTIGLIDE;
+				_GP(game).chars[i].flags &= ~CHF_ANTIGLIDE;
 		}
 	}
 
-	if ((opt == OPT_CROSSFADEMUSIC) && (game.audioClipTypes.size() > AUDIOTYPE_LEGACY_MUSIC)) {
+	if ((opt == OPT_CROSSFADEMUSIC) && (_GP(game).audioClipTypes.size() > AUDIOTYPE_LEGACY_MUSIC)) {
 		// legacy compatibility -- changing crossfade speed here also
 		// updates the new audio clip type style
-		game.audioClipTypes[AUDIOTYPE_LEGACY_MUSIC].crossfadeSpeed = setting;
+		_GP(game).audioClipTypes[AUDIOTYPE_LEGACY_MUSIC].crossfadeSpeed = setting;
 	}
 
-	int oldval = game.options[opt];
-	game.options[opt] = setting;
+	int oldval = _GP(game).options[opt];
+	_GP(game).options[opt] = setting;
 
 	if (opt == OPT_DUPLICATEINV)
 		update_invorder();
 	else if (opt == OPT_DISABLEOFF)
-		gui_disabled_style = convert_gui_disabled_style(game.options[OPT_DISABLEOFF]);
+		gui_disabled_style = convert_gui_disabled_style(_GP(game).options[OPT_DISABLEOFF]);
 	else if (opt == OPT_PORTRAITSIDE) {
 		if (setting == 0)  // set back to Left
 			play.swap_portrait_side = 0;
@@ -435,17 +435,17 @@ int GetGameOption(int opt) {
 	if (((opt < 1) || (opt > OPT_HIGHESTOPTION)) && (opt != OPT_LIPSYNCTEXT))
 		quit("!GetGameOption: invalid option specified");
 
-	return game.options[opt];
+	return _GP(game).options[opt];
 }
 
 void SkipUntilCharacterStops(int cc) {
 	if (!is_valid_character(cc))
 		quit("!SkipUntilCharacterStops: invalid character specified");
-	if (game.chars[cc].room != displayed_room)
+	if (_GP(game).chars[cc].room != displayed_room)
 		quit("!SkipUntilCharacterStops: specified character not in current room");
 
 	// if they are not currently moving, do nothing
-	if (!game.chars[cc].walking)
+	if (!_GP(game).chars[cc].walking)
 		return;
 
 	if (is_in_cutscene())
@@ -546,7 +546,7 @@ void GetLocationName(int xxx, int yyy, char *tempo) {
 			if (play.get_loc_name_last_time != 1000 + mover)
 				guis_need_update = 1;
 			play.get_loc_name_last_time = 1000 + mover;
-			strcpy(tempo, get_translation(game.invinfo[mover].name));
+			strcpy(tempo, get_translation(_GP(game).invinfo[mover].name));
 		} else if ((play.get_loc_name_last_time > 1000) && (play.get_loc_name_last_time < 1000 + MAX_INV)) {
 			// no longer selecting an item
 			guis_need_update = 1;
@@ -576,7 +576,7 @@ void GetLocationName(int xxx, int yyy, char *tempo) {
 	// on character
 	if (loctype == LOCTYPE_CHAR) {
 		onhs = getloctype_index;
-		strcpy(tempo, get_translation(game.chars[onhs].name));
+		strcpy(tempo, get_translation(_GP(game).chars[onhs].name));
 		if (play.get_loc_name_last_time != 2000 + onhs)
 			guis_need_update = 1;
 		play.get_loc_name_last_time = 2000 + onhs;
@@ -897,7 +897,7 @@ void RoomProcessClick(int xx, int yy, int mood) {
 	xx = vpt.first.X;
 	yy = vpt.first.Y;
 
-	if ((mood == MODE_WALK) && (game.options[OPT_NOWALKMODE] == 0)) {
+	if ((mood == MODE_WALK) && (_GP(game).options[OPT_NOWALKMODE] == 0)) {
 		int hsnum = get_hotspot_at(xx, yy);
 		if (hsnum < 1);
 		else if (thisroom.Hotspots[hsnum].WalkTo.X < 1);
@@ -907,7 +907,7 @@ void RoomProcessClick(int xx, int yy, int mood) {
 			yy = thisroom.Hotspots[hsnum].WalkTo.Y;
 			debug_script_log("Move to walk-to point hotspot %d", hsnum);
 		}
-		walk_character(game.playercharacter, xx, yy, 0, true);
+		walk_character(_GP(game).playercharacter, xx, yy, 0, true);
 		return;
 	}
 	play.usedmode = mood;
@@ -936,7 +936,7 @@ int IsInteractionAvailable(int xx, int yy, int mood) {
 	yy = vpt.first.Y;
 
 	// You can always walk places
-	if ((mood == MODE_WALK) && (game.options[OPT_NOWALKMODE] == 0))
+	if ((mood == MODE_WALK) && (_GP(game).options[OPT_NOWALKMODE] == 0))
 		return 1;
 
 	play.check_interaction_only = 1;
@@ -969,13 +969,13 @@ void GetMessageText(int msg, char *buffer) {
 }
 
 void SetSpeechFont(int fontnum) {
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!SetSpeechFont: invalid font number.");
 	play.speech_font = fontnum;
 }
 
 void SetNormalFont(int fontnum) {
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!SetNormalFont: invalid font number.");
 	play.normal_font = fontnum;
 }
@@ -1011,7 +1011,7 @@ int WaitImpl(int skip_type, int nloops) {
 
 	GameLoopUntilValueIsZero(&play.wait_counter);
 
-	if (game.options[OPT_BASESCRIPTAPI] < kScriptAPI_v351) {
+	if (_GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v351) {
 		// < 3.5.1 return 1 is skipped by user input, otherwise 0
 		return (play.wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK)) != 0 ? 1 : 0;
 	}
diff --git a/engines/ags/engine/ac/global_gui.cpp b/engines/ags/engine/ac/global_gui.cpp
index 6ffeacfdd6..56a53bc3be 100644
--- a/engines/ags/engine/ac/global_gui.cpp
+++ b/engines/ags/engine/ac/global_gui.cpp
@@ -35,16 +35,17 @@
 #include "ags/shared/gui/guimain.h"
 #include "ags/engine/script/runtimescriptvalue.h"
 #include "ags/shared/util/string_compat.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
+
 extern ScriptGUI *scrGui;
 
 int IsGUIOn(int guinum) {
-	if ((guinum < 0) || (guinum >= game.numgui))
+	if ((guinum < 0) || (guinum >= _GP(game).numgui))
 		quit("!IsGUIOn: invalid GUI number specified");
 	return (guis[guinum].IsDisplayed()) ? 1 : 0;
 }
@@ -52,7 +53,7 @@ int IsGUIOn(int guinum) {
 // This is an internal script function, and is undocumented.
 // It is used by the editor's automatic macro generation.
 int FindGUIID(const char *GUIName) {
-	for (int ii = 0; ii < game.numgui; ii++) {
+	for (int ii = 0; ii < _GP(game).numgui; ii++) {
 		if (guis[ii].Name.IsEmpty())
 			continue;
 		if (strcmp(guis[ii].Name, GUIName) == 0)
@@ -65,7 +66,7 @@ int FindGUIID(const char *GUIName) {
 }
 
 void InterfaceOn(int ifn) {
-	if ((ifn < 0) | (ifn >= game.numgui))
+	if ((ifn < 0) | (ifn >= _GP(game).numgui))
 		quit("!GUIOn: invalid GUI specified");
 
 	EndSkippingUntilCharStops();
@@ -85,7 +86,7 @@ void InterfaceOn(int ifn) {
 }
 
 void InterfaceOff(int ifn) {
-	if ((ifn < 0) | (ifn >= game.numgui)) quit("!GUIOff: invalid GUI specified");
+	if ((ifn < 0) | (ifn >= _GP(game).numgui)) quit("!GUIOff: invalid GUI specified");
 	if (!guis[ifn].IsVisible()) {
 		debug_script_log("GUIOff(%d) ignored (already off)", ifn);
 		return;
@@ -104,7 +105,7 @@ void InterfaceOff(int ifn) {
 }
 
 void SetGUIObjectEnabled(int guin, int objn, int enabled) {
-	if ((guin < 0) || (guin >= game.numgui))
+	if ((guin < 0) || (guin >= _GP(game).numgui))
 		quit("!SetGUIObjectEnabled: invalid GUI number");
 	if ((objn < 0) || (objn >= guis[guin].GetControlCount()))
 		quit("!SetGUIObjectEnabled: invalid object number");
@@ -113,7 +114,7 @@ void SetGUIObjectEnabled(int guin, int objn, int enabled) {
 }
 
 void SetGUIObjectPosition(int guin, int objn, int xx, int yy) {
-	if ((guin < 0) || (guin >= game.numgui))
+	if ((guin < 0) || (guin >= _GP(game).numgui))
 		quit("!SetGUIObjectPosition: invalid GUI number");
 	if ((objn < 0) || (objn >= guis[guin].GetControlCount()))
 		quit("!SetGUIObjectPosition: invalid object number");
@@ -122,14 +123,14 @@ void SetGUIObjectPosition(int guin, int objn, int xx, int yy) {
 }
 
 void SetGUIPosition(int ifn, int xx, int yy) {
-	if ((ifn < 0) || (ifn >= game.numgui))
+	if ((ifn < 0) || (ifn >= _GP(game).numgui))
 		quit("!SetGUIPosition: invalid GUI number");
 
 	GUI_SetPosition(&scrGui[ifn], xx, yy);
 }
 
 void SetGUIObjectSize(int ifn, int objn, int newwid, int newhit) {
-	if ((ifn < 0) || (ifn >= game.numgui))
+	if ((ifn < 0) || (ifn >= _GP(game).numgui))
 		quit("!SetGUIObjectSize: invalid GUI number");
 
 	if ((objn < 0) || (objn >= guis[ifn].GetControlCount()))
@@ -139,21 +140,21 @@ void SetGUIObjectSize(int ifn, int objn, int newwid, int newhit) {
 }
 
 void SetGUISize(int ifn, int widd, int hitt) {
-	if ((ifn < 0) || (ifn >= game.numgui))
+	if ((ifn < 0) || (ifn >= _GP(game).numgui))
 		quit("!SetGUISize: invalid GUI number");
 
 	GUI_SetSize(&scrGui[ifn], widd, hitt);
 }
 
 void SetGUIZOrder(int guin, int z) {
-	if ((guin < 0) || (guin >= game.numgui))
+	if ((guin < 0) || (guin >= _GP(game).numgui))
 		quit("!SetGUIZOrder: invalid GUI number");
 
 	GUI_SetZOrder(&scrGui[guin], z);
 }
 
 void SetGUIClickable(int guin, int clickable) {
-	if ((guin < 0) || (guin >= game.numgui))
+	if ((guin < 0) || (guin >= _GP(game).numgui))
 		quit("!SetGUIClickable: invalid GUI number");
 
 	GUI_SetClickable(&scrGui[guin], clickable);
@@ -161,14 +162,14 @@ void SetGUIClickable(int guin, int clickable) {
 
 // pass trans=0 for fully solid, trans=100 for fully transparent
 void SetGUITransparency(int ifn, int trans) {
-	if ((ifn < 0) | (ifn >= game.numgui))
+	if ((ifn < 0) | (ifn >= _GP(game).numgui))
 		quit("!SetGUITransparency: invalid GUI number");
 
 	GUI_SetTransparency(&scrGui[ifn], trans);
 }
 
 void CentreGUI(int ifn) {
-	if ((ifn < 0) | (ifn >= game.numgui))
+	if ((ifn < 0) | (ifn >= _GP(game).numgui))
 		quit("!CentreGUI: invalid GUI number");
 
 	GUI_Centre(&scrGui[ifn]);
@@ -176,7 +177,7 @@ void CentreGUI(int ifn) {
 
 int GetTextWidth(const char *text, int fontnum) {
 	VALIDATE_STRING(text);
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!GetTextWidth: invalid font number.");
 
 	return game_to_data_coord(wgettextwidth_compensate(text, fontnum));
@@ -184,7 +185,7 @@ int GetTextWidth(const char *text, int fontnum) {
 
 int GetTextHeight(const char *text, int fontnum, int width) {
 	VALIDATE_STRING(text);
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!GetTextHeight: invalid font number.");
 
 	if (break_up_text_into_lines(text, Lines, data_to_game_coord(width), fontnum) == 0)
@@ -193,19 +194,19 @@ int GetTextHeight(const char *text, int fontnum, int width) {
 }
 
 int GetFontHeight(int fontnum) {
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!GetFontHeight: invalid font number.");
 	return game_to_data_coord(getfontheight_outlined(fontnum));
 }
 
 int GetFontLineSpacing(int fontnum) {
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!GetFontLineSpacing: invalid font number.");
 	return game_to_data_coord(getfontspacing_outlined(fontnum));
 }
 
 void SetGUIBackgroundPic(int guin, int slotn) {
-	if ((guin < 0) | (guin >= game.numgui))
+	if ((guin < 0) | (guin >= _GP(game).numgui))
 		quit("!SetGUIBackgroundPic: invalid GUI number");
 
 	GUI_SetBackgroundGraphic(&scrGui[guin], slotn);
@@ -242,7 +243,7 @@ int GetGUIAt(int xx, int yy) {
 	data_to_game_coords(&xx, &yy);
 
 	int aa, ll;
-	for (ll = game.numgui - 1; ll >= 0; ll--) {
+	for (ll = _GP(game).numgui - 1; ll >= 0; ll--) {
 		aa = play.gui_draw_order[ll];
 		if (guis[aa].IsInteractableAt(xx, yy))
 			return aa;
@@ -251,16 +252,16 @@ int GetGUIAt(int xx, int yy) {
 }
 
 void SetTextWindowGUI(int guinum) {
-	if ((guinum < -1) | (guinum >= game.numgui))
+	if ((guinum < -1) | (guinum >= _GP(game).numgui))
 		quit("!SetTextWindowGUI: invalid GUI number");
 
 	if (guinum < 0);  // disable it
 	else if (!guis[guinum].IsTextWindow())
 		quit("!SetTextWindowGUI: specified GUI is not a text window");
 
-	if (play.speech_textwindow_gui == game.options[OPT_TWCUSTOM])
+	if (play.speech_textwindow_gui == _GP(game).options[OPT_TWCUSTOM])
 		play.speech_textwindow_gui = guinum;
-	game.options[OPT_TWCUSTOM] = guinum;
+	_GP(game).options[OPT_TWCUSTOM] = guinum;
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_hotspot.cpp b/engines/ags/engine/ac/global_hotspot.cpp
index 6998213c1e..11cc70377e 100644
--- a/engines/ags/engine/ac/global_hotspot.cpp
+++ b/engines/ags/engine/ac/global_hotspot.cpp
@@ -36,6 +36,7 @@
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/shared/game/roomstruct.h"
 #include "ags/engine/script/script.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -44,7 +45,7 @@ using namespace AGS::Shared;
 extern RoomStruct thisroom;
 extern RoomStatus *croom;
 extern CharacterInfo *playerchar;
-extern GameSetupStruct game;
+
 
 
 void DisableHotspot(int hsnum) {
@@ -111,10 +112,10 @@ void RunHotspotInteraction(int hotspothere, int mood) {
 		play.usedinv = cdata;
 	}
 
-	if ((game.options[OPT_WALKONLOOK] == 0) & (mood == MODE_LOOK));
+	if ((_GP(game).options[OPT_WALKONLOOK] == 0) & (mood == MODE_LOOK));
 	else if (play.auto_use_walkto_points == 0);
 	else if ((mood != MODE_WALK) && (play.check_interaction_only == 0))
-		MoveCharacterToHotspot(game.playercharacter, hotspothere);
+		MoveCharacterToHotspot(_GP(game).playercharacter, hotspothere);
 
 	// can't use the setevent functions because this ProcessClick is only
 	// executed once in a eventlist
diff --git a/engines/ags/engine/ac/global_inventoryitem.cpp b/engines/ags/engine/ac/global_inventoryitem.cpp
index baf99555e1..3485c6691d 100644
--- a/engines/ags/engine/ac/global_inventoryitem.cpp
+++ b/engines/ags/engine/ac/global_inventoryitem.cpp
@@ -33,13 +33,13 @@
 #include "ags/shared/gui/guiinv.h"
 #include "ags/engine/ac/event.h"
 #include "ags/engine/ac/gamestate.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 extern int mouse_ifacebut_xoffs, mouse_ifacebut_yoffs;
 extern const char *evblockbasename;
@@ -48,29 +48,29 @@ extern CharacterInfo *playerchar;
 
 
 void set_inv_item_pic(int invi, int piccy) {
-	if ((invi < 1) || (invi > game.numinvitems))
+	if ((invi < 1) || (invi > _GP(game).numinvitems))
 		quit("!SetInvItemPic: invalid inventory item specified");
 
-	if (game.invinfo[invi].pic == piccy)
+	if (_GP(game).invinfo[invi].pic == piccy)
 		return;
 
-	if (game.invinfo[invi].pic == game.invinfo[invi].cursorPic) {
+	if (_GP(game).invinfo[invi].pic == _GP(game).invinfo[invi].cursorPic) {
 		// Backwards compatibility -- there didn't used to be a cursorPic,
 		// so if they're the same update both.
 		set_inv_item_cursorpic(invi, piccy);
 	}
 
-	game.invinfo[invi].pic = piccy;
+	_GP(game).invinfo[invi].pic = piccy;
 	guis_need_update = 1;
 }
 
 void SetInvItemName(int invi, const char *newName) {
-	if ((invi < 1) || (invi > game.numinvitems))
+	if ((invi < 1) || (invi > _GP(game).numinvitems))
 		quit("!SetInvName: invalid inventory item specified");
 
 	// set the new name, making sure it doesn't overflow the buffer
-	strncpy(game.invinfo[invi].name, newName, 25);
-	game.invinfo[invi].name[24] = 0;
+	strncpy(_GP(game).invinfo[invi].name, newName, 25);
+	_GP(game).invinfo[invi].name[24] = 0;
 
 	// might need to redraw the GUI if it has the inv item name on it
 	guis_need_update = 1;
@@ -98,18 +98,18 @@ int GetInvAt(int xxx, int yyy) {
 
 void GetInvName(int indx, char *buff) {
 	VALIDATE_STRING(buff);
-	if ((indx < 0) | (indx >= game.numinvitems)) quit("!GetInvName: invalid inventory item specified");
-	strcpy(buff, get_translation(game.invinfo[indx].name));
+	if ((indx < 0) | (indx >= _GP(game).numinvitems)) quit("!GetInvName: invalid inventory item specified");
+	strcpy(buff, get_translation(_GP(game).invinfo[indx].name));
 }
 
 int GetInvGraphic(int indx) {
-	if ((indx < 0) | (indx >= game.numinvitems)) quit("!GetInvGraphic: invalid inventory item specified");
+	if ((indx < 0) | (indx >= _GP(game).numinvitems)) quit("!GetInvGraphic: invalid inventory item specified");
 
-	return game.invinfo[indx].pic;
+	return _GP(game).invinfo[indx].pic;
 }
 
 void RunInventoryInteraction(int iit, int modd) {
-	if ((iit < 0) || (iit >= game.numinvitems))
+	if ((iit < 0) || (iit >= _GP(game).numinvitems))
 		quit("!RunInventoryInteraction: invalid inventory number");
 
 	evblocknum = iit;
@@ -144,11 +144,11 @@ int IsInventoryInteractionAvailable(int item, int mood) {
 }
 
 int GetInvProperty(int item, const char *property) {
-	return get_int_property(game.invProps[item], play.invProps[item], property);
+	return get_int_property(_GP(game).invProps[item], play.invProps[item], property);
 }
 
 void GetInvPropertyText(int item, const char *property, char *bufer) {
-	get_text_property(game.invProps[item], play.invProps[item], property, bufer);
+	get_text_property(_GP(game).invProps[item], play.invProps[item], property, bufer);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_label.cpp b/engines/ags/engine/ac/global_label.cpp
index a60e6f23d6..03b6c089b1 100644
--- a/engines/ags/engine/ac/global_label.cpp
+++ b/engines/ags/engine/ac/global_label.cpp
@@ -26,15 +26,14 @@
 #include "ags/engine/ac/label.h"
 #include "ags/engine/ac/string.h"
 #include "ags/shared/gui/guimain.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
-
 void SetLabelColor(int guin, int objn, int colr) {
-	if ((guin < 0) | (guin >= game.numgui))
+	if ((guin < 0) | (guin >= _GP(game).numgui))
 		quit("!SetLabelColor: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount()))
 		quit("!SetLabelColor: invalid object number");
@@ -47,7 +46,7 @@ void SetLabelColor(int guin, int objn, int colr) {
 
 void SetLabelText(int guin, int objn, const char *newtx) {
 	VALIDATE_STRING(newtx);
-	if ((guin < 0) | (guin >= game.numgui)) quit("!SetLabelText: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!SetLabelText: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!SetLabelTexT: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUILabel)
 		quit("!SetLabelText: specified control is not a label");
@@ -58,7 +57,7 @@ void SetLabelText(int guin, int objn, const char *newtx) {
 
 void SetLabelFont(int guin, int objn, int fontnum) {
 
-	if ((guin < 0) | (guin >= game.numgui)) quit("!SetLabelFont: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!SetLabelFont: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!SetLabelFont: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUILabel)
 		quit("!SetLabelFont: specified control is not a label");
diff --git a/engines/ags/engine/ac/global_object.cpp b/engines/ags/engine/ac/global_object.cpp
index a2b552eba3..590bf7789f 100644
--- a/engines/ags/engine/ac/global_object.cpp
+++ b/engines/ags/engine/ac/global_object.cpp
@@ -44,6 +44,7 @@
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/shared/gfx/gfx_def.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -54,12 +55,12 @@ using namespace AGS::Shared;
 extern RoomStatus *croom;
 extern RoomObject *objs;
 extern ViewStruct *views;
-extern GameSetupStruct game;
+
 extern ObjectCache objcache[MAX_ROOM_OBJECTS];
 extern RoomStruct thisroom;
 extern CharacterInfo *playerchar;
 extern int displayed_room;
-extern SpriteCache spriteset;
+
 extern int actSpsCount;
 extern Bitmap **actsps;
 extern IDriverDependantBitmap **actspsbmp;
@@ -142,8 +143,8 @@ void RemoveObjectTint(int obj) {
 void SetObjectView(int obn, int vii) {
 	if (!is_valid_object(obn)) quit("!SetObjectView: invalid object number specified");
 	debug_script_log("Object %d set to view %d", obn, vii);
-	if ((vii < 1) || (vii > game.numviews)) {
-		quitprintf("!SetObjectView: invalid view number (You said %d, max is %d)", vii, game.numviews);
+	if ((vii < 1) || (vii > _GP(game).numviews)) {
+		quitprintf("!SetObjectView: invalid view number (You said %d, max is %d)", vii, _GP(game).numviews);
 	}
 	vii--;
 
@@ -158,7 +159,7 @@ void SetObjectView(int obn, int vii) {
 void SetObjectFrame(int obn, int viw, int lop, int fra) {
 	if (!is_valid_object(obn)) quit("!SetObjectFrame: invalid object number specified");
 	viw--;
-	if (viw < 0 || viw >= game.numviews) quitprintf("!SetObjectFrame: invalid view number used (%d, range is 0 - %d)", viw, game.numviews - 1);
+	if (viw < 0 || viw >= _GP(game).numviews) quitprintf("!SetObjectFrame: invalid view number used (%d, range is 0 - %d)", viw, _GP(game).numviews - 1);
 	if (lop < 0 || lop >= views[viw].numLoops) quitprintf("!SetObjectFrame: invalid loop number used (%d, range is 0 - %d)", lop, views[viw].numLoops - 1);
 	// AGS < 3.5.1 let user to pass literally any positive invalid frame value by silently reassigning it to zero...
 	if (loaded_game_file_version < kGameVersion_351) {
@@ -274,7 +275,7 @@ void MergeObject(int obn) {
 	int xpos = data_to_game_coord(objs[obn].x);
 	int ypos = (data_to_game_coord(objs[obn].y) - theHeight);
 
-	draw_sprite_support_alpha(bg_frame.get(), false, xpos, ypos, actsps[obn], (game.SpriteInfos[objs[obn].num].Flags & SPF_ALPHACHANNEL) != 0);
+	draw_sprite_support_alpha(bg_frame.get(), false, xpos, ypos, actsps[obn], (_GP(game).SpriteInfos[objs[obn].num].Flags & SPF_ALPHACHANNEL) != 0);
 	invalidate_screen();
 	mark_current_background_dirty();
 
@@ -392,7 +393,7 @@ void SetObjectClickable(int cha, int clik) {
 void SetObjectIgnoreWalkbehinds(int cha, int clik) {
 	if (!is_valid_object(cha))
 		quit("!SetObjectIgnoreWalkbehinds: Invalid object specified");
-	if (game.options[OPT_BASESCRIPTAPI] >= kScriptAPI_v350)
+	if (_GP(game).options[OPT_BASESCRIPTAPI] >= kScriptAPI_v350)
 		debug_script_warn("IgnoreWalkbehinds is not recommended for use, consider other solutions");
 	objs[cha].flags &= ~OBJF_NOWALKBEHINDS;
 	if (clik)
@@ -443,14 +444,14 @@ int AreObjectsColliding(int obj1, int obj2) {
 
 int GetThingRect(int thing, _Rect *rect) {
 	if (is_valid_character(thing)) {
-		if (game.chars[thing].room != displayed_room)
+		if (_GP(game).chars[thing].room != displayed_room)
 			return 0;
 
 		int charwid = game_to_data_coord(GetCharacterWidth(thing));
-		rect->x1 = game.chars[thing].x - (charwid / 2);
+		rect->x1 = _GP(game).chars[thing].x - (charwid / 2);
 		rect->x2 = rect->x1 + charwid;
-		rect->y1 = game.chars[thing].get_effective_y() - game_to_data_coord(GetCharacterHeight(thing));
-		rect->y2 = game.chars[thing].get_effective_y();
+		rect->y1 = _GP(game).chars[thing].get_effective_y() - game_to_data_coord(GetCharacterHeight(thing));
+		rect->y2 = _GP(game).chars[thing].get_effective_y();
 	} else if (is_valid_object(thing - OVERLAPPING_OBJECT)) {
 		int objid = thing - OVERLAPPING_OBJECT;
 		if (objs[objid].on != 1)
@@ -515,7 +516,7 @@ Bitmap *GetObjectImage(int obj, int *isFlipped) {
 			return actsps[obj];
 		}
 	}
-	return spriteset[objs[obj].num];
+	return _GP(spriteset)[objs[obj].num];
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_overlay.cpp b/engines/ags/engine/ac/global_overlay.cpp
index 9fe39315a1..4b9cc06b63 100644
--- a/engines/ags/engine/ac/global_overlay.cpp
+++ b/engines/ags/engine/ac/global_overlay.cpp
@@ -34,15 +34,13 @@
 #include "ags/shared/ac/spritecache.h"
 #include "ags/engine/ac/system.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace Shared;
 using namespace Engine;
 
-extern SpriteCache spriteset;
-extern GameSetupStruct game;
-
 
 
 void RemoveOverlay(int ovrid) {
@@ -53,9 +51,9 @@ void RemoveOverlay(int ovrid) {
 int CreateGraphicOverlay(int xx, int yy, int slott, int trans) {
 	data_to_game_coords(&xx, &yy);
 
-	Bitmap *screeno = BitmapHelper::CreateTransparentBitmap(game.SpriteInfos[slott].Width, game.SpriteInfos[slott].Height, game.GetColorDepth());
-	wputblock(screeno, 0, 0, spriteset[slott], trans);
-	bool hasAlpha = (game.SpriteInfos[slott].Flags & SPF_ALPHACHANNEL) != 0;
+	Bitmap *screeno = BitmapHelper::CreateTransparentBitmap(_GP(game).SpriteInfos[slott].Width, _GP(game).SpriteInfos[slott].Height, _GP(game).GetColorDepth());
+	wputblock(screeno, 0, 0, _GP(spriteset)[slott], trans);
+	bool hasAlpha = (_GP(game).SpriteInfos[slott].Flags & SPF_ALPHACHANNEL) != 0;
 	int nse = add_screen_overlay(xx, yy, OVER_CUSTOM, screeno, hasAlpha);
 	return screenover[nse].type;
 }
diff --git a/engines/ags/engine/ac/global_palette.cpp b/engines/ags/engine/ac/global_palette.cpp
index 17961ad2f5..2d82202521 100644
--- a/engines/ags/engine/ac/global_palette.cpp
+++ b/engines/ags/engine/ac/global_palette.cpp
@@ -25,18 +25,17 @@
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/ac/gamestate.h"
 #include "ags/engine/ac/global_palette.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
 extern GameState play;
 extern color palette[256];
 
-
 void CyclePalette(int strt, int eend) {
 	// hi-color game must invalidate screen since the palette changes
 	// the effect of the drawing operations
-	if (game.color_depth > 1)
+	if (_GP(game).color_depth > 1)
 		invalidate_screen();
 
 	if ((strt < 0) || (strt > 255) || (eend < 0) || (eend > 255))
@@ -54,7 +53,7 @@ void CyclePalette(int strt, int eend) {
 
 }
 void SetPalRGB(int inndx, int rr, int gg, int bb) {
-	if (game.color_depth > 1)
+	if (_GP(game).color_depth > 1)
 		invalidate_screen();
 
 	wsetrgb(inndx, rr, gg, bb, palette);
@@ -68,7 +67,7 @@ get_palette(pptr);
 }*/
 
 void UpdatePalette() {
-	if (game.color_depth > 1)
+	if (_GP(game).color_depth > 1)
 		invalidate_screen();
 
 	if (!play.fast_forward)
diff --git a/engines/ags/engine/ac/global_room.cpp b/engines/ags/engine/ac/global_room.cpp
index 43ec2bae8d..33e34c5766 100644
--- a/engines/ags/engine/ac/global_room.cpp
+++ b/engines/ags/engine/ac/global_room.cpp
@@ -38,13 +38,14 @@
 #include "ags/engine/debugging/debugger.h"
 #include "ags/engine/script/script.h"
 #include "ags/shared/util/math.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace Shared;
 
 extern GameState play;
-extern GameSetupStruct game;
+
 extern RoomStatus *croom;
 extern CharacterInfo *playerchar;
 extern int displayed_room;
@@ -130,7 +131,7 @@ void NewRoom(int nrnum) {
 			// nasty hack - make sure it doesn't move the character
 			// to a walkable area
 			mls[playerchar->walking].direct = 1;
-			StopMoving(game.playercharacter);
+			StopMoving(_GP(game).playercharacter);
 		}
 	} else if (in_graph_script)
 		gs_to_newroom = nrnum;
@@ -144,10 +145,10 @@ void NewRoomEx(int nrnum, int newx, int newy) {
 void NewRoomNPC(int charid, int nrnum, int newx, int newy) {
 	if (!is_valid_character(charid))
 		quit("!NewRoomNPC: invalid character");
-	if (charid == game.playercharacter)
+	if (charid == _GP(game).playercharacter)
 		quit("!NewRoomNPC: use NewRoomEx with the player character");
 
-	Character_ChangeRoom(&game.chars[charid], nrnum, newx, newy);
+	Character_ChangeRoom(&_GP(game).chars[charid], nrnum, newx, newy);
 }
 
 void ResetRoom(int nrnum) {
diff --git a/engines/ags/engine/ac/global_screen.cpp b/engines/ags/engine/ac/global_screen.cpp
index 52a0c628ad..2dff91e985 100644
--- a/engines/ags/engine/ac/global_screen.cpp
+++ b/engines/ags/engine/ac/global_screen.cpp
@@ -34,6 +34,7 @@
 #include "ags/engine/platform/base/agsplatformdriver.h"
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -42,7 +43,7 @@ using namespace AGS::Engine;
 
 extern GameSetup usetup;
 extern GameState play;
-extern GameSetupStruct game;
+
 extern RoomStruct thisroom;
 extern IGraphicsDriver *gfxDriver;
 extern AGSPlatformDriver *platform;
@@ -142,7 +143,7 @@ void my_fade_out(int spdd) {
 	if (play.screen_is_faded_out == 0)
 		gfxDriver->FadeOut(spdd, play.fade_to_red, play.fade_to_green, play.fade_to_blue);
 
-	if (game.color_depth > 1)
+	if (_GP(game).color_depth > 1)
 		play.screen_is_faded_out = 1;
 }
 
diff --git a/engines/ags/engine/ac/global_slider.cpp b/engines/ags/engine/ac/global_slider.cpp
index 36845f9440..98324a51bf 100644
--- a/engines/ags/engine/ac/global_slider.cpp
+++ b/engines/ags/engine/ac/global_slider.cpp
@@ -26,15 +26,14 @@
 #include "ags/engine/ac/slider.h"
 #include "ags/shared/gui/guimain.h"
 #include "ags/shared/gui/guislider.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
-
 void SetSliderValue(int guin, int objn, int valn) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!SetSliderValue: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!SetSliderValue: invalid GUI number");
 	if (guis[guin].GetControlType(objn) != kGUISlider)
 		quit("!SetSliderValue: specified control is not a slider");
 
@@ -43,7 +42,7 @@ void SetSliderValue(int guin, int objn, int valn) {
 }
 
 int GetSliderValue(int guin, int objn) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!GetSliderValue: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!GetSliderValue: invalid GUI number");
 	if (guis[guin].GetControlType(objn) != kGUISlider)
 		quit("!GetSliderValue: specified control is not a slider");
 
diff --git a/engines/ags/engine/ac/global_string.cpp b/engines/ags/engine/ac/global_string.cpp
index 38f74bdb93..3bd4c2c515 100644
--- a/engines/ags/engine/ac/global_string.cpp
+++ b/engines/ags/engine/ac/global_string.cpp
@@ -52,7 +52,7 @@ void _sc_strcat(char *s1, const char *s2) {
 	VALIDATE_STRING(s2);
 	check_strlen(s1);
 	int mosttocopy = (MAXSTRLEN - strlen(s1)) - 1;
-	//  int numbf=game.iface[4].numbuttons;
+	//  int numbf=_GP(game).iface[4].numbuttons;
 	my_strncpy(&s1[strlen(s1)], s2, mosttocopy);
 }
 
diff --git a/engines/ags/engine/ac/global_textbox.cpp b/engines/ags/engine/ac/global_textbox.cpp
index 34a4d1d04a..da9e124d36 100644
--- a/engines/ags/engine/ac/global_textbox.cpp
+++ b/engines/ags/engine/ac/global_textbox.cpp
@@ -27,16 +27,17 @@
 #include "ags/engine/ac/textbox.h"
 #include "ags/shared/gui/guimain.h"
 #include "ags/shared/gui/guitextbox.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
+
 
 void SetTextBoxFont(int guin, int objn, int fontnum) {
 
-	if ((guin < 0) | (guin >= game.numgui)) quit("!SetTextBoxFont: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!SetTextBoxFont: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!SetTextBoxFont: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUITextBox)
 		quit("!SetTextBoxFont: specified control is not a text box");
@@ -47,7 +48,7 @@ void SetTextBoxFont(int guin, int objn, int fontnum) {
 
 void GetTextBoxText(int guin, int objn, char *txbuf) {
 	VALIDATE_STRING(txbuf);
-	if ((guin < 0) | (guin >= game.numgui)) quit("!GetTextBoxText: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!GetTextBoxText: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!GetTextBoxText: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUITextBox)
 		quit("!GetTextBoxText: specified control is not a text box");
@@ -57,7 +58,7 @@ void GetTextBoxText(int guin, int objn, char *txbuf) {
 }
 
 void SetTextBoxText(int guin, int objn, const char *txbuf) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!SetTextBoxText: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!SetTextBoxText: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!SetTextBoxText: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUITextBox)
 		quit("!SetTextBoxText: specified control is not a text box");
diff --git a/engines/ags/engine/ac/global_viewframe.cpp b/engines/ags/engine/ac/global_viewframe.cpp
index 8ede616427..f4a823af07 100644
--- a/engines/ags/engine/ac/global_viewframe.cpp
+++ b/engines/ags/engine/ac/global_viewframe.cpp
@@ -26,15 +26,14 @@
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/engine/media/audio/audio_system.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
 extern ViewStruct *views;
 
-
 void SetFrameSound(int vii, int loop, int frame, int sound) {
-	if ((vii < 1) || (vii > game.numviews))
+	if ((vii < 1) || (vii > _GP(game).numviews))
 		quit("!SetFrameSound: invalid view number");
 	vii--;
 
@@ -47,11 +46,11 @@ void SetFrameSound(int vii, int loop, int frame, int sound) {
 	if (sound < 1) {
 		views[vii].loops[loop].frames[frame].sound = -1;
 	} else {
-		ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(game, false, sound);
+		ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(_GP(game), false, sound);
 		if (clip == nullptr)
 			quitprintf("!SetFrameSound: audio clip aSound%d not found", sound);
 
-		views[vii].loops[loop].frames[frame].sound = clip->id + (game.IsLegacyAudioSystem() ? 0x10000000 : 0);
+		views[vii].loops[loop].frames[frame].sound = clip->id + (_GP(game).IsLegacyAudioSystem() ? 0x10000000 : 0);
 	}
 }
 
diff --git a/engines/ags/engine/ac/gui.cpp b/engines/ags/engine/ac/gui.cpp
index d76d399ca6..3b775f7499 100644
--- a/engines/ags/engine/ac/gui.cpp
+++ b/engines/ags/engine/ac/gui.cpp
@@ -57,7 +57,7 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -70,7 +70,7 @@ extern RoomStruct thisroom;
 extern int cur_mode, cur_cursor;
 extern ccInstance *gameinst;
 extern ScriptGUI *scrGui;
-extern GameSetupStruct game;
+
 extern CCGUIObject ccDynamicGUIObject;
 extern Bitmap **guibg;
 extern IDriverDependantBitmap **guibgbmp;
@@ -443,7 +443,7 @@ void update_gui_zorder() {
 	int numdone = 0, b;
 
 	// for each GUI
-	for (int a = 0; a < game.numgui; a++) {
+	for (int a = 0; a < _GP(game).numgui; a++) {
 		// find the right place in the draw order array
 		int insertAt = numdone;
 		for (b = 0; b < numdone; b++) {
@@ -511,7 +511,7 @@ void update_gui_disabled_status() {
 
 	if (all_buttons_was != all_buttons_disabled) {
 		// GUIs might have been removed/added
-		for (int aa = 0; aa < game.numgui; aa++) {
+		for (int aa = 0; aa < _GP(game).numgui; aa++) {
 			guis[aa].OnControlPositionChanged();
 		}
 		guis_need_update = 1;
@@ -521,10 +521,10 @@ void update_gui_disabled_status() {
 
 
 int adjust_x_for_guis(int xx, int yy) {
-	if ((game.options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0))
+	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0))
 		return xx;
 	// If it's covered by a GUI, move it right a bit
-	for (int aa = 0; aa < game.numgui; aa++) {
+	for (int aa = 0; aa < _GP(game).numgui; aa++) {
 		if (!guis[aa].IsDisplayed())
 			continue;
 		if ((guis[aa].X > xx) || (guis[aa].Y > yy) || (guis[aa].Y + guis[aa].Height < yy))
@@ -544,10 +544,10 @@ int adjust_x_for_guis(int xx, int yy) {
 }
 
 int adjust_y_for_guis(int yy) {
-	if ((game.options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0))
+	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0))
 		return yy;
 	// If it's covered by a GUI, move it down a bit
-	for (int aa = 0; aa < game.numgui; aa++) {
+	for (int aa = 0; aa < _GP(game).numgui; aa++) {
 		if (!guis[aa].IsDisplayed())
 			continue;
 		if (guis[aa].Y > yy)
@@ -569,7 +569,7 @@ int adjust_y_for_guis(int yy) {
 void recreate_guibg_image(GUIMain *tehgui) {
 	int ifn = tehgui->ID;
 	delete guibg[ifn];
-	guibg[ifn] = BitmapHelper::CreateBitmap(tehgui->Width, tehgui->Height, game.GetColorDepth());
+	guibg[ifn] = BitmapHelper::CreateBitmap(tehgui->Width, tehgui->Height, _GP(game).GetColorDepth());
 	if (guibg[ifn] == nullptr)
 		quit("SetGUISize: internal error: unable to reallocate gui cache");
 	guibg[ifn] = ReplaceBitmapWithSupportedFormat(guibg[ifn]);
@@ -583,7 +583,7 @@ void recreate_guibg_image(GUIMain *tehgui) {
 extern int is_complete_overlay;
 
 int gui_get_interactable(int x, int y) {
-	if ((game.options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0))
+	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0))
 		return -1;
 	return GetGUIAt(x, y);
 }
@@ -591,12 +591,12 @@ int gui_get_interactable(int x, int y) {
 int gui_on_mouse_move() {
 	int mouse_over_gui = -1;
 	// If all GUIs are off, skip the loop
-	if ((game.options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0));
+	if ((_GP(game).options[OPT_DISABLEOFF] == 3) && (all_buttons_disabled > 0));
 	else {
 		// Scan for mouse-y-pos GUIs, and pop one up if appropriate
 		// Also work out the mouse-over GUI while we're at it
 		int ll;
-		for (ll = 0; ll < game.numgui; ll++) {
+		for (ll = 0; ll < _GP(game).numgui; ll++) {
 			const int guin = play.gui_draw_order[ll];
 			if (guis[guin].IsInteractableAt(_G(mousex), _G(mousey))) mouse_over_gui = guin;
 
@@ -652,7 +652,7 @@ void gui_on_mouse_up(const int wasongui, const int wasbutdown) {
 			if (iit >= 0) {
 				evblocknum = iit;
 				play.used_inv_on = iit;
-				if (game.options[OPT_HANDLEINVCLICKS]) {
+				if (_GP(game).options[OPT_HANDLEINVCLICKS]) {
 					// Let the script handle the click
 					// LEFTINV is 5, RIGHTINV is 6
 					force_event(EV_TEXTSCRIPT, TS_MCLICK, wasbutdown + 4);
diff --git a/engines/ags/engine/ac/guicontrol.cpp b/engines/ags/engine/ac/guicontrol.cpp
index e198f72c7d..b061db762d 100644
--- a/engines/ags/engine/ac/guicontrol.cpp
+++ b/engines/ags/engine/ac/guicontrol.cpp
@@ -37,7 +37,7 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/ac/guiinv.cpp b/engines/ags/engine/ac/guiinv.cpp
index b7a2767e45..fd8b78b864 100644
--- a/engines/ags/engine/ac/guiinv.cpp
+++ b/engines/ags/engine/ac/guiinv.cpp
@@ -28,14 +28,13 @@
 #include "ags/engine/ac/characterextras.h"
 #include "ags/shared/ac/spritecache.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
 extern int gui_disabled_style;
 extern GameState play;
 extern CharacterExtras *charextra;
-extern SpriteCache spriteset;
 
 
 namespace AGS {
@@ -43,7 +42,7 @@ namespace Shared {
 
 int GUIInvWindow::GetCharacterId() const {
 	if (CharId < 0)
-		return game.playercharacter;
+		return _GP(game).playercharacter;
 
 	return CharId;
 }
@@ -56,7 +55,7 @@ void GUIInvWindow::Draw(Bitmap *ds) {
 	// backwards compatibility
 	play.inv_numinline = ColCount;
 	play.inv_numdisp = RowCount * ColCount;
-	play.obsolete_inv_numorder = charextra[game.playercharacter].invorder_count;
+	play.obsolete_inv_numorder = charextra[_GP(game).playercharacter].invorder_count;
 	// if the user changes top_inv_item, switch into backwards
 	// compatibiltiy mode
 	if (play.inv_top)
@@ -74,7 +73,7 @@ void GUIInvWindow::Draw(Bitmap *ds) {
 
 	for (int item = TopItem; item < lastItem; ++item) {
 		// draw inv graphic
-		draw_gui_sprite(ds, game.invinfo[charextra[GetCharacterId()].invorder[item]].pic, at_x, at_y, true);
+		draw_gui_sprite(ds, _GP(game).invinfo[charextra[GetCharacterId()].invorder[item]].pic, at_x, at_y, true);
 		at_x += data_to_game_coord(ItemWidth);
 
 		// go to next row when appropriate
diff --git a/engines/ags/engine/ac/inventoryitem.cpp b/engines/ags/engine/ac/inventoryitem.cpp
index 8701a874d2..428e1ecdb0 100644
--- a/engines/ags/engine/ac/inventoryitem.cpp
+++ b/engines/ags/engine/ac/inventoryitem.cpp
@@ -37,22 +37,21 @@
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
 extern ScriptInvItem scrInv[MAX_INV];
 extern int cur_cursor;
 extern CharacterInfo *playerchar;
 extern CCInventory ccDynamicInv;
 
-
 void InventoryItem_SetCursorGraphic(ScriptInvItem *iitem, int newSprite) {
 	set_inv_item_cursorpic(iitem->id, newSprite);
 }
 
 int InventoryItem_GetCursorGraphic(ScriptInvItem *iitem) {
-	return game.invinfo[iitem->id].cursorPic;
+	return _GP(game).invinfo[iitem->id].cursorPic;
 }
 
 void InventoryItem_SetGraphic(ScriptInvItem *iitem, int piccy) {
@@ -79,11 +78,11 @@ void InventoryItem_GetName(ScriptInvItem *iitem, char *buff) {
 }
 
 const char *InventoryItem_GetName_New(ScriptInvItem *invitem) {
-	return CreateNewScriptString(get_translation(game.invinfo[invitem->id].name));
+	return CreateNewScriptString(get_translation(_GP(game).invinfo[invitem->id].name));
 }
 
 int InventoryItem_GetGraphic(ScriptInvItem *iitem) {
-	return game.invinfo[iitem->id].pic;
+	return _GP(game).invinfo[iitem->id].pic;
 }
 
 void InventoryItem_RunInteraction(ScriptInvItem *iitem, int mood) {
@@ -95,15 +94,15 @@ int InventoryItem_CheckInteractionAvailable(ScriptInvItem *iitem, int mood) {
 }
 
 int InventoryItem_GetProperty(ScriptInvItem *scii, const char *property) {
-	return get_int_property(game.invProps[scii->id], play.invProps[scii->id], property);
+	return get_int_property(_GP(game).invProps[scii->id], play.invProps[scii->id], property);
 }
 
 void InventoryItem_GetPropertyText(ScriptInvItem *scii, const char *property, char *bufer) {
-	get_text_property(game.invProps[scii->id], play.invProps[scii->id], property, bufer);
+	get_text_property(_GP(game).invProps[scii->id], play.invProps[scii->id], property, bufer);
 }
 
 const char *InventoryItem_GetTextProperty(ScriptInvItem *scii, const char *property) {
-	return get_text_property_dynamic_string(game.invProps[scii->id], play.invProps[scii->id], property);
+	return get_text_property_dynamic_string(_GP(game).invProps[scii->id], play.invProps[scii->id], property);
 }
 
 bool InventoryItem_SetProperty(ScriptInvItem *scii, const char *property, int value) {
@@ -117,7 +116,7 @@ bool InventoryItem_SetTextProperty(ScriptInvItem *scii, const char *property, co
 //=============================================================================
 
 void set_inv_item_cursorpic(int invItemId, int piccy) {
-	game.invinfo[invItemId].cursorPic = piccy;
+	_GP(game).invinfo[invItemId].cursorPic = piccy;
 
 	if ((cur_cursor == MODE_USE) && (playerchar->activeinv == invItemId)) {
 		update_inv_cursor(invItemId);
diff --git a/engines/ags/engine/ac/invwindow.cpp b/engines/ags/engine/ac/invwindow.cpp
index a0a336d2e3..45c1dd4f90 100644
--- a/engines/ags/engine/ac/invwindow.cpp
+++ b/engines/ags/engine/ac/invwindow.cpp
@@ -47,18 +47,18 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 extern CharacterExtras *charextra;
 extern ScriptInvItem scrInv[MAX_INV];
 extern int mouse_ifacebut_xoffs, mouse_ifacebut_yoffs;
-extern SpriteCache spriteset;
+
 extern int evblocknum;
 extern CharacterInfo *playerchar;
 extern AGSPlatformDriver *platform;
@@ -84,7 +84,7 @@ CharacterInfo *InvWindow_GetCharacterToUse(GUIInvWindow *guii) {
 	if (guii->CharId < 0)
 		return nullptr;
 
-	return &game.chars[guii->CharId];
+	return &_GP(game).chars[guii->CharId];
 }
 
 void InvWindow_SetItemWidth(GUIInvWindow *guii, int newwidth) {
@@ -237,11 +237,11 @@ void InventoryScreen::Prepare() {
 	// Fun fact: this fallback does not seem to be intentional, and was a
 	// coincidental result of SpriteCache incorrectly remembering "last seeked
 	// sprite" as 2041/2042/2043 while in fact stream was after sprite 0.
-	if (spriteset[2041] == nullptr || spriteset[2042] == nullptr || spriteset[2043] == nullptr)
+	if (_GP(spriteset)[2041] == nullptr || _GP(spriteset)[2042] == nullptr || _GP(spriteset)[2043] == nullptr)
 		debug_script_warn("InventoryScreen: one or more of the inventory screen graphics (sprites 2041, 2042, 2043) does not exist, fallback to sprites 0, 1, 2 instead");
-	btn_look_sprite = spriteset[2041] != nullptr ? 2041 : 0;
-	btn_select_sprite = spriteset[2042] != nullptr ? 2042 : (spriteset[1] != nullptr ? 1 : 0);
-	btn_ok_sprite = spriteset[2043] != nullptr ? 2043 : (spriteset[2] != nullptr ? 2 : 0);
+	btn_look_sprite = _GP(spriteset)[2041] != nullptr ? 2041 : 0;
+	btn_select_sprite = _GP(spriteset)[2042] != nullptr ? 2042 : (_GP(spriteset)[1] != nullptr ? 1 : 0);
+	btn_ok_sprite = _GP(spriteset)[2043] != nullptr ? 2043 : (_GP(spriteset)[2] != nullptr ? 2 : 0);
 
 	break_code = 0;
 }
@@ -250,9 +250,9 @@ int InventoryScreen::Redraw() {
 	numitems = 0;
 	widest = 0;
 	highest = 0;
-	if (charextra[game.playercharacter].invorder_count < 0)
+	if (charextra[_GP(game).playercharacter].invorder_count < 0)
 		update_invorder();
-	if (charextra[game.playercharacter].invorder_count == 0) {
+	if (charextra[_GP(game).playercharacter].invorder_count == 0) {
 		DisplayMessage(996);
 		in_inv_screen--;
 		return -1;
@@ -264,17 +264,17 @@ int InventoryScreen::Redraw() {
 		return -1;
 	}
 
-	for (int i = 0; i < charextra[game.playercharacter].invorder_count; ++i) {
-		if (game.invinfo[charextra[game.playercharacter].invorder[i]].name[0] != 0) {
-			dii[numitems].num = charextra[game.playercharacter].invorder[i];
-			dii[numitems].sprnum = game.invinfo[charextra[game.playercharacter].invorder[i]].pic;
+	for (int i = 0; i < charextra[_GP(game).playercharacter].invorder_count; ++i) {
+		if (_GP(game).invinfo[charextra[_GP(game).playercharacter].invorder[i]].name[0] != 0) {
+			dii[numitems].num = charextra[_GP(game).playercharacter].invorder[i];
+			dii[numitems].sprnum = _GP(game).invinfo[charextra[_GP(game).playercharacter].invorder[i]].pic;
 			int snn = dii[numitems].sprnum;
-			if (game.SpriteInfos[snn].Width > widest) widest = game.SpriteInfos[snn].Width;
-			if (game.SpriteInfos[snn].Height > highest) highest = game.SpriteInfos[snn].Height;
+			if (_GP(game).SpriteInfos[snn].Width > widest) widest = _GP(game).SpriteInfos[snn].Width;
+			if (_GP(game).SpriteInfos[snn].Height > highest) highest = _GP(game).SpriteInfos[snn].Height;
 			numitems++;
 		}
 	}
-	if (numitems != charextra[game.playercharacter].invorder_count)
+	if (numitems != charextra[_GP(game).playercharacter].invorder_count)
 		quit("inconsistent inventory calculations");
 
 	widest += get_fixed_pixel_size(4);
@@ -312,15 +312,15 @@ void InventoryScreen::Draw(Bitmap *ds) {
 	for (int i = top_item; i < numitems; ++i) {
 		if (i >= top_item + num_visible_items)
 			break;
-		Bitmap *spof = spriteset[dii[i].sprnum];
+		Bitmap *spof = _GP(spriteset)[dii[i].sprnum];
 		wputblock(ds, barxp + 1 + ((i - top_item) % 4) * widest + widest / 2 - spof->GetWidth() / 2,
 			bartop + 1 + ((i - top_item) / 4) * highest + highest / 2 - spof->GetHeight() / 2, spof, 1);
 	}
-#define BUTTONWID Math::Max(1, game.SpriteInfos[btn_select_sprite].Width)
+#define BUTTONWID Math::Max(1, _GP(game).SpriteInfos[btn_select_sprite].Width)
 	// Draw select, look and OK buttons
-	wputblock(ds, 2, buttonyp + get_fixed_pixel_size(2), spriteset[btn_look_sprite], 1);
-	wputblock(ds, 3 + BUTTONWID, buttonyp + get_fixed_pixel_size(2), spriteset[btn_select_sprite], 1);
-	wputblock(ds, 4 + BUTTONWID * 2, buttonyp + get_fixed_pixel_size(2), spriteset[btn_ok_sprite], 1);
+	wputblock(ds, 2, buttonyp + get_fixed_pixel_size(2), _GP(spriteset)[btn_look_sprite], 1);
+	wputblock(ds, 3 + BUTTONWID, buttonyp + get_fixed_pixel_size(2), _GP(spriteset)[btn_select_sprite], 1);
+	wputblock(ds, 4 + BUTTONWID * 2, buttonyp + get_fixed_pixel_size(2), _GP(spriteset)[btn_ok_sprite], 1);
 
 	// Draw Up and Down buttons if required
 	Bitmap *arrowblock = BitmapHelper::CreateTransparentBitmap(ARROWBUTTONWID, ARROWBUTTONWID);
diff --git a/engines/ags/engine/ac/label.cpp b/engines/ags/engine/ac/label.cpp
index 92876a3188..45455d0761 100644
--- a/engines/ags/engine/ac/label.cpp
+++ b/engines/ags/engine/ac/label.cpp
@@ -20,21 +20,20 @@
  *
  */
 
-//include <string.h>
 #include "ags/engine/ac/label.h"
 #include "ags/shared/ac/common.h"
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/ac/global_translation.h"
 #include "ags/engine/ac/string.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
+
 
 // ** LABEL FUNCTIONS
 
@@ -82,7 +81,7 @@ int Label_GetFont(GUILabel *labl) {
 }
 
 void Label_SetFont(GUILabel *guil, int fontnum) {
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!SetLabelFont: invalid font number.");
 
 	if (fontnum != guil->Font) {
diff --git a/engines/ags/engine/ac/listbox.cpp b/engines/ags/engine/ac/listbox.cpp
index c24a6a2db4..2e8a32b1e3 100644
--- a/engines/ags/engine/ac/listbox.cpp
+++ b/engines/ags/engine/ac/listbox.cpp
@@ -36,16 +36,17 @@
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
+#include "ags/ags.h"
 #include "common/fs.h"
 #include "common/savefile.h"
-#include "ags/ags.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
 extern GameState play;
-extern GameSetupStruct game;
+
 
 // *** LIST BOX FUNCTIONS
 
@@ -215,7 +216,7 @@ int ListBox_GetFont(GUIListBox *listbox) {
 
 void ListBox_SetFont(GUIListBox *listbox, int newfont) {
 
-	if ((newfont < 0) || (newfont >= game.numfonts))
+	if ((newfont < 0) || (newfont >= _GP(game).numfonts))
 		quit("!ListBox.Font: invalid font number.");
 
 	if (newfont != listbox->Font) {
@@ -365,7 +366,7 @@ void ListBox_ScrollUp(GUIListBox *listbox) {
 
 
 GUIListBox *is_valid_listbox(int guin, int objn) {
-	if ((guin < 0) | (guin >= game.numgui)) quit("!ListBox: invalid GUI number");
+	if ((guin < 0) | (guin >= _GP(game).numgui)) quit("!ListBox: invalid GUI number");
 	if ((objn < 0) | (objn >= guis[guin].GetControlCount())) quit("!ListBox: invalid object number");
 	if (guis[guin].GetControlType(objn) != kGUIListBox)
 		quit("!ListBox: specified control is not a list box");
diff --git a/engines/ags/engine/ac/mouse.cpp b/engines/ags/engine/ac/mouse.cpp
index 8d12af0650..f66f5cc3d3 100644
--- a/engines/ags/engine/ac/mouse.cpp
+++ b/engines/ags/engine/ac/mouse.cpp
@@ -45,17 +45,17 @@
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/global_game.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 extern ScriptSystem scsystem;
-extern SpriteCache spriteset;
+
 extern CharacterInfo *playerchar;
 extern IGraphicsDriver *gfxDriver;
 
@@ -116,11 +116,11 @@ void SetMouseBounds(int x1, int y1, int x2, int y2) {
 // mouse cursor functions:
 // set_mouse_cursor: changes visual appearance to specified cursor
 void set_mouse_cursor(int newcurs) {
-	const int hotspotx = game.mcurs[newcurs].hotx, hotspoty = game.mcurs[newcurs].hoty;
+	const int hotspotx = _GP(game).mcurs[newcurs].hotx, hotspoty = _GP(game).mcurs[newcurs].hoty;
 	msethotspot(hotspotx, hotspoty);
 
 	// if it's same cursor and there's animation in progress, then don't assign a new pic just yet
-	if (newcurs == cur_cursor && game.mcurs[newcurs].view >= 0 &&
+	if (newcurs == cur_cursor && _GP(game).mcurs[newcurs].view >= 0 &&
 		(mouse_frame > 0 || mouse_delay > 0)) {
 		return;
 	}
@@ -133,28 +133,28 @@ void set_mouse_cursor(int newcurs) {
 	}
 
 	// Assign new pic
-	set_new_cursor_graphic(game.mcurs[newcurs].pic);
+	set_new_cursor_graphic(_GP(game).mcurs[newcurs].pic);
 	delete dotted_mouse_cursor;
 	dotted_mouse_cursor = nullptr;
 
 	// If it's inventory cursor, draw hotspot crosshair sprite upon it
-	if ((newcurs == MODE_USE) && (game.mcurs[newcurs].pic > 0) &&
-		((game.hotdot > 0) || (game.invhotdotsprite > 0))) {
+	if ((newcurs == MODE_USE) && (_GP(game).mcurs[newcurs].pic > 0) &&
+		((_GP(game).hotdot > 0) || (_GP(game).invhotdotsprite > 0))) {
 		// If necessary, create a copy of the cursor and put the hotspot
 		// dot onto it
 		dotted_mouse_cursor = BitmapHelper::CreateBitmapCopy(_G(mousecurs)[0]);
 
-		if (game.invhotdotsprite > 0) {
+		if (_GP(game).invhotdotsprite > 0) {
 			draw_sprite_slot_support_alpha(dotted_mouse_cursor,
-				(game.SpriteInfos[game.mcurs[newcurs].pic].Flags & SPF_ALPHACHANNEL) != 0,
-				hotspotx - game.SpriteInfos[game.invhotdotsprite].Width / 2,
-				hotspoty - game.SpriteInfos[game.invhotdotsprite].Height / 2,
-				game.invhotdotsprite);
+				(_GP(game).SpriteInfos[_GP(game).mcurs[newcurs].pic].Flags & SPF_ALPHACHANNEL) != 0,
+				hotspotx - _GP(game).SpriteInfos[_GP(game).invhotdotsprite].Width / 2,
+				hotspoty - _GP(game).SpriteInfos[_GP(game).invhotdotsprite].Height / 2,
+				_GP(game).invhotdotsprite);
 		} else {
-			putpixel_compensate(dotted_mouse_cursor, hotspotx, hotspoty, MakeColor(game.hotdot));
+			putpixel_compensate(dotted_mouse_cursor, hotspotx, hotspoty, MakeColor(_GP(game).hotdot));
 
-			if (game.hotdotouter > 0) {
-				int outercol = MakeColor(game.hotdotouter);
+			if (_GP(game).hotdotouter > 0) {
+				int outercol = MakeColor(_GP(game).hotdotouter);
 
 				putpixel_compensate(dotted_mouse_cursor, hotspotx + get_fixed_pixel_size(1), hotspoty, outercol);
 				putpixel_compensate(dotted_mouse_cursor, hotspotx, hotspoty + get_fixed_pixel_size(1), outercol);
@@ -174,41 +174,41 @@ void set_default_cursor() {
 
 // permanently change cursor graphic
 void ChangeCursorGraphic(int curs, int newslot) {
-	if ((curs < 0) || (curs >= game.numcursors))
+	if ((curs < 0) || (curs >= _GP(game).numcursors))
 		quit("!ChangeCursorGraphic: invalid mouse cursor");
 
-	if ((curs == MODE_USE) && (game.options[OPT_FIXEDINVCURSOR] == 0))
+	if ((curs == MODE_USE) && (_GP(game).options[OPT_FIXEDINVCURSOR] == 0))
 		debug_script_warn("Mouse.ChangeModeGraphic should not be used on the Inventory cursor when the cursor is linked to the active inventory item");
 
-	game.mcurs[curs].pic = newslot;
-	spriteset.Precache(newslot);
+	_GP(game).mcurs[curs].pic = newslot;
+	_GP(spriteset).Precache(newslot);
 	if (curs == cur_mode)
 		set_mouse_cursor(curs);
 }
 
 int Mouse_GetModeGraphic(int curs) {
-	if ((curs < 0) || (curs >= game.numcursors))
+	if ((curs < 0) || (curs >= _GP(game).numcursors))
 		quit("!Mouse.GetModeGraphic: invalid mouse cursor");
 
-	return game.mcurs[curs].pic;
+	return _GP(game).mcurs[curs].pic;
 }
 
 void ChangeCursorHotspot(int curs, int x, int y) {
-	if ((curs < 0) || (curs >= game.numcursors))
+	if ((curs < 0) || (curs >= _GP(game).numcursors))
 		quit("!ChangeCursorHotspot: invalid mouse cursor");
-	game.mcurs[curs].hotx = data_to_game_coord(x);
-	game.mcurs[curs].hoty = data_to_game_coord(y);
+	_GP(game).mcurs[curs].hotx = data_to_game_coord(x);
+	_GP(game).mcurs[curs].hoty = data_to_game_coord(y);
 	if (curs == cur_cursor)
 		set_mouse_cursor(cur_cursor);
 }
 
 void Mouse_ChangeModeView(int curs, int newview) {
-	if ((curs < 0) || (curs >= game.numcursors))
+	if ((curs < 0) || (curs >= _GP(game).numcursors))
 		quit("!Mouse.ChangeModeView: invalid mouse cursor");
 
 	newview--;
 
-	game.mcurs[curs].view = newview;
+	_GP(game).mcurs[curs].view = newview;
 
 	if (newview >= 0) {
 		precache_view(newview);
@@ -228,11 +228,11 @@ void SetPreviousCursor() {
 
 // set_cursor_mode: changes mode and appearance
 void set_cursor_mode(int newmode) {
-	if ((newmode < 0) || (newmode >= game.numcursors))
+	if ((newmode < 0) || (newmode >= _GP(game).numcursors))
 		quit("!SetCursorMode: invalid cursor mode specified");
 
 	guis_need_update = 1;
-	if (game.mcurs[newmode].flags & MCF_DISABLED) {
+	if (_GP(game).mcurs[newmode].flags & MCF_DISABLED) {
 		find_next_enabled_cursor(newmode);
 		return;
 	}
@@ -250,11 +250,11 @@ void set_cursor_mode(int newmode) {
 }
 
 void enable_cursor_mode(int modd) {
-	game.mcurs[modd].flags &= ~MCF_DISABLED;
+	_GP(game).mcurs[modd].flags &= ~MCF_DISABLED;
 	// now search the interfaces for related buttons to re-enable
 	int uu, ww;
 
-	for (uu = 0; uu < game.numgui; uu++) {
+	for (uu = 0; uu < _GP(game).numgui; uu++) {
 		for (ww = 0; ww < guis[uu].GetControlCount(); ww++) {
 			if (guis[uu].GetControlType(ww) != kGUIButton) continue;
 			GUIButton *gbpt = (GUIButton *)guis[uu].GetControl(ww);
@@ -267,11 +267,11 @@ void enable_cursor_mode(int modd) {
 }
 
 void disable_cursor_mode(int modd) {
-	game.mcurs[modd].flags |= MCF_DISABLED;
+	_GP(game).mcurs[modd].flags |= MCF_DISABLED;
 	// now search the interfaces for related buttons to kill
 	int uu, ww;
 
-	for (uu = 0; uu < game.numgui; uu++) {
+	for (uu = 0; uu < _GP(game).numgui; uu++) {
 		for (ww = 0; ww < guis[uu].GetControlCount(); ww++) {
 			if (guis[uu].GetControlType(ww) != kGUIButton) continue;
 			GUIButton *gbpt = (GUIButton *)guis[uu].GetControl(ww);
@@ -320,9 +320,9 @@ int IsButtonDown(int which) {
 }
 
 int IsModeEnabled(int which) {
-	return (which < 0) || (which >= game.numcursors) ? 0 :
+	return (which < 0) || (which >= _GP(game).numcursors) ? 0 :
 		which == MODE_USE ? playerchar->activeinv > 0 :
-	(game.mcurs[which].flags & MCF_DISABLED) == 0;
+	(_GP(game).mcurs[which].flags & MCF_DISABLED) == 0;
 }
 
 void Mouse_EnableControl(bool on) {
@@ -358,24 +358,24 @@ void update_script_mouse_coords() {
 
 void update_inv_cursor(int invnum) {
 
-	if ((game.options[OPT_FIXEDINVCURSOR] == 0) && (invnum > 0)) {
-		int cursorSprite = game.invinfo[invnum].cursorPic;
+	if ((_GP(game).options[OPT_FIXEDINVCURSOR] == 0) && (invnum > 0)) {
+		int cursorSprite = _GP(game).invinfo[invnum].cursorPic;
 
 		// Fall back to the inventory pic if no cursor pic is defined.
 		if (cursorSprite == 0)
-			cursorSprite = game.invinfo[invnum].pic;
+			cursorSprite = _GP(game).invinfo[invnum].pic;
 
-		game.mcurs[MODE_USE].pic = cursorSprite;
+		_GP(game).mcurs[MODE_USE].pic = cursorSprite;
 		// all cursor images must be pre-cached
-		spriteset.Precache(cursorSprite);
+		_GP(spriteset).Precache(cursorSprite);
 
-		if ((game.invinfo[invnum].hotx > 0) || (game.invinfo[invnum].hoty > 0)) {
+		if ((_GP(game).invinfo[invnum].hotx > 0) || (_GP(game).invinfo[invnum].hoty > 0)) {
 			// if the hotspot was set (unfortunately 0,0 isn't a valid co-ord)
-			game.mcurs[MODE_USE].hotx = game.invinfo[invnum].hotx;
-			game.mcurs[MODE_USE].hoty = game.invinfo[invnum].hoty;
+			_GP(game).mcurs[MODE_USE].hotx = _GP(game).invinfo[invnum].hotx;
+			_GP(game).mcurs[MODE_USE].hoty = _GP(game).invinfo[invnum].hoty;
 		} else {
-			game.mcurs[MODE_USE].hotx = game.SpriteInfos[cursorSprite].Width / 2;
-			game.mcurs[MODE_USE].hoty = game.SpriteInfos[cursorSprite].Height / 2;
+			_GP(game).mcurs[MODE_USE].hotx = _GP(game).SpriteInfos[cursorSprite].Width / 2;
+			_GP(game).mcurs[MODE_USE].hoty = _GP(game).SpriteInfos[cursorSprite].Height / 2;
 		}
 	}
 }
@@ -387,18 +387,18 @@ void update_cached_mouse_cursor() {
 }
 
 void set_new_cursor_graphic(int spriteslot) {
-	_G(mousecurs)[0] = spriteset[spriteslot];
+	_G(mousecurs)[0] = _GP(spriteset)[spriteslot];
 
 	// It looks like spriteslot 0 can be used in games with version 2.72 and lower.
 	// The NULL check should ensure that the sprite is valid anyway.
 	if (((spriteslot < 1) && (loaded_game_file_version > kGameVersion_272)) || (_G(mousecurs)[0] == nullptr)) {
 		if (blank_mouse_cursor == nullptr) {
-			blank_mouse_cursor = BitmapHelper::CreateTransparentBitmap(1, 1, game.GetColorDepth());
+			blank_mouse_cursor = BitmapHelper::CreateTransparentBitmap(1, 1, _GP(game).GetColorDepth());
 		}
 		_G(mousecurs)[0] = blank_mouse_cursor;
 	}
 
-	if (game.SpriteInfos[spriteslot].Flags & SPF_ALPHACHANNEL)
+	if (_GP(game).SpriteInfos[spriteslot].Flags & SPF_ALPHACHANNEL)
 		alpha_blend_cursor = 1;
 	else
 		alpha_blend_cursor = 0;
@@ -407,27 +407,27 @@ void set_new_cursor_graphic(int spriteslot) {
 }
 
 bool is_standard_cursor_enabled(int curs) {
-	if ((game.mcurs[curs].flags & MCF_DISABLED) == 0) {
+	if ((_GP(game).mcurs[curs].flags & MCF_DISABLED) == 0) {
 		// inventory cursor, and they have an active item
 		if (curs == MODE_USE) {
 			if (playerchar->activeinv > 0)
 				return true;
 		}
 		// standard cursor that's not disabled, go with it
-		else if (game.mcurs[curs].flags & MCF_STANDARD)
+		else if (_GP(game).mcurs[curs].flags & MCF_STANDARD)
 			return true;
 	}
 	return false;
 }
 
 int find_next_enabled_cursor(int startwith) {
-	if (startwith >= game.numcursors)
+	if (startwith >= _GP(game).numcursors)
 		startwith = 0;
 	int testing = startwith;
 	do {
 		if (is_standard_cursor_enabled(testing)) break;
 		testing++;
-		if (testing >= game.numcursors) testing = 0;
+		if (testing >= _GP(game).numcursors) testing = 0;
 	} while (testing != startwith);
 
 	if (testing != startwith)
@@ -438,12 +438,12 @@ int find_next_enabled_cursor(int startwith) {
 
 int find_previous_enabled_cursor(int startwith) {
 	if (startwith < 0)
-		startwith = game.numcursors - 1;
+		startwith = _GP(game).numcursors - 1;
 	int testing = startwith;
 	do {
 		if (is_standard_cursor_enabled(testing)) break;
 		testing--;
-		if (testing < 0) testing = game.numcursors - 1;
+		if (testing < 0) testing = _GP(game).numcursors - 1;
 	} while (testing != startwith);
 
 	if (testing != startwith)
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index 64871509e8..a3a26afad2 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -45,17 +45,16 @@
 #include "ags/engine/script/runtimescriptvalue.h"
 #include "ags/engine/ac/dynobj/cc_object.h"
 #include "ags/engine/ac/movelist.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
 extern ScriptObject scrObj[MAX_ROOM_OBJECTS];
 extern RoomStatus *croom;
 extern RoomObject *objs;
@@ -63,7 +62,7 @@ extern ViewStruct *views;
 extern RoomStruct thisroom;
 extern ObjectCache objcache[MAX_ROOM_OBJECTS];
 extern MoveList *mls;
-extern GameSetupStruct game;
+
 extern Bitmap *walkable_areas_temp;
 extern IGraphicsDriver *gfxDriver;
 extern CCObject ccDynamicObject;
@@ -101,13 +100,13 @@ void Object_RemoveTint(ScriptObject *objj) {
 }
 
 void Object_SetView(ScriptObject *objj, int view, int loop, int frame) {
-	if (game.options[OPT_BASESCRIPTAPI] < kScriptAPI_v351) {
+	if (_GP(game).options[OPT_BASESCRIPTAPI] < kScriptAPI_v351) {
 		// Previous version of SetView had negative loop and frame mean "use latest values"
 		auto &obj = objs[objj->id];
 		if (loop < 0) loop = obj.loop;
 		if (frame < 0) frame = obj.frame;
 		const int vidx = view - 1;
-		if (vidx < 0 || vidx >= game.numviews) quit("!Object_SetView: invalid view number used");
+		if (vidx < 0 || vidx >= _GP(game).numviews) quit("!Object_SetView: invalid view number used");
 		loop = Math::Clamp(loop, 0, (int)views[vidx].numLoops - 1);
 		frame = Math::Clamp(frame, 0, (int)views[vidx].loops[loop].numFrames - 1);
 	}
@@ -440,7 +439,7 @@ void move_object(int objj, int tox, int toy, int spee, int ignwal) {
 	set_route_move_speed(spee, spee);
 	set_color_depth(8);
 	int mslot = find_route(objX, objY, tox, toy, prepare_walkable_areas(-1), objj + 1, 1, ignwal);
-	set_color_depth(game.GetColorDepth());
+	set_color_depth(_GP(game).GetColorDepth());
 	if (mslot > 0) {
 		objs[objj].moving = mslot;
 		mls[mslot].direct = ignwal;
@@ -521,7 +520,7 @@ int is_pos_in_sprite(int xx, int yy, int arx, int ary, Bitmap *sprit, int spww,
 	if (isposinbox(xx, yy, arx, ary, arx + spww, ary + sphh) == FALSE)
 		return FALSE;
 
-	if (game.options[OPT_PIXPERFECT]) {
+	if (_GP(game).options[OPT_PIXPERFECT]) {
 		// if it's transparent, or off the edge of the sprite, ignore
 		int xpos = data_to_game_coord(xx - arx);
 		int ypos = data_to_game_coord(yy - ary);
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 269bb5dc74..9c990ace12 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -37,25 +37,22 @@
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/script/runtimescriptvalue.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
 extern int displayed_room;
 extern int face_talking;
 extern ViewStruct *views;
 extern CharacterExtras *charextra;
 extern IGraphicsDriver *gfxDriver;
 
-
-
 std::vector<ScreenOverlay> screenover;
 int is_complete_overlay = 0, is_text_overlay = 0;
 
@@ -241,11 +238,11 @@ void get_overlay_position(const ScreenOverlay &over, int *x, int *y) {
 		int charid = over.y;
 
 		auto view = FindNearestViewport(charid);
-		const int charpic = views[game.chars[charid].view].loops[game.chars[charid].loop].frames[0].pic;
-		const int height = (charextra[charid].height < 1) ? game.SpriteInfos[charpic].Height : charextra[charid].height;
+		const int charpic = views[_GP(game).chars[charid].view].loops[_GP(game).chars[charid].loop].frames[0].pic;
+		const int height = (charextra[charid].height < 1) ? _GP(game).SpriteInfos[charpic].Height : charextra[charid].height;
 		Point screenpt = view->RoomToScreen(
-			data_to_game_coord(game.chars[charid].x),
-			data_to_game_coord(game.chars[charid].get_effective_y()) - height).first;
+			data_to_game_coord(_GP(game).chars[charid].x),
+			data_to_game_coord(_GP(game).chars[charid].get_effective_y()) - height).first;
 		tdxp = screenpt.X - over.pic->GetWidth() / 2;
 		if (tdxp < 0) tdxp = 0;
 		tdyp = screenpt.Y - get_fixed_pixel_size(5);
@@ -254,7 +251,7 @@ void get_overlay_position(const ScreenOverlay &over, int *x, int *y) {
 
 		if ((tdxp + over.pic->GetWidth()) >= ui_view.GetWidth())
 			tdxp = (ui_view.GetWidth() - over.pic->GetWidth()) - 1;
-		if (game.chars[charid].room != displayed_room) {
+		if (_GP(game).chars[charid].room != displayed_room) {
 			tdxp = ui_view.GetWidth() / 2 - over.pic->GetWidth() / 2;
 			tdyp = ui_view.GetHeight() / 2 - over.pic->GetHeight() / 2;
 		}
diff --git a/engines/ags/engine/ac/parser.cpp b/engines/ags/engine/ac/parser.cpp
index ec949675ad..9aadb74034 100644
--- a/engines/ags/engine/ac/parser.cpp
+++ b/engines/ags/engine/ac/parser.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-//include <cctype> //isalnum()
-//include <cstdio>
 #include "ags/shared/ac/common.h"
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/ac/gamestate.h"
@@ -31,17 +29,17 @@
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/shared/util/string.h"
 #include "ags/shared/util/string_compat.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 
 int Parser_FindWordID(const char *wordToFind) {
@@ -71,12 +69,12 @@ int Said(const char *checkwords) {
 
 int find_word_in_dictionary(const char *lookfor) {
 	int j;
-	if (game.dict == nullptr)
+	if (_GP(game).dict == nullptr)
 		return -1;
 
-	for (j = 0; j < game.dict->num_words; j++) {
-		if (ags_stricmp(lookfor, game.dict->word[j]) == 0) {
-			return game.dict->wordnum[j];
+	for (j = 0; j < _GP(game).dict->num_words; j++) {
+		if (ags_stricmp(lookfor, _GP(game).dict->word[j]) == 0) {
+			return _GP(game).dict->wordnum[j];
 		}
 	}
 	if (lookfor[0] != 0) {
diff --git a/engines/ags/engine/ac/properties.cpp b/engines/ags/engine/ac/properties.cpp
index 04988a487e..1aa5b17e0c 100644
--- a/engines/ags/engine/ac/properties.cpp
+++ b/engines/ags/engine/ac/properties.cpp
@@ -27,19 +27,19 @@
 #include "ags/engine/ac/dynobj/scriptstring.h"
 #include "ags/engine/script/runtimescriptvalue.h"
 #include "ags/shared/util/string_utils.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern GameSetupStruct game;
 extern ScriptString myScriptStringImpl;
 
 // begin custom property functions
 
 bool get_property_desc(PropertyDesc &desc, const char *property, PropertyType want_type) {
-	PropertySchema::const_iterator sch_it = game.propSchema.find(property);
-	if (sch_it == game.propSchema.end())
+	PropertySchema::const_iterator sch_it = _GP(game).propSchema.find(property);
+	if (sch_it == _GP(game).propSchema.end())
 		quit("!GetProperty: no such property found in schema. Make sure you are using the property's name, and not its description, when calling this command.");
 
 	desc = sch_it->_value;
diff --git a/engines/ags/engine/ac/region.cpp b/engines/ags/engine/ac/region.cpp
index 22d628828e..c97134c7fd 100644
--- a/engines/ags/engine/ac/region.cpp
+++ b/engines/ags/engine/ac/region.cpp
@@ -31,10 +31,10 @@
 #include "ags/engine/ac/dynobj/scriptdrawingsurface.h"
 #include "ags/shared/game/roomstruct.h"
 #include "ags/engine/script/runtimescriptvalue.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -43,7 +43,7 @@ using namespace AGS::Shared;
 extern ScriptRegion scrRegion[MAX_ROOM_REGIONS];
 extern RoomStruct thisroom;
 extern RoomStatus *croom;
-extern GameSetupStruct game;
+
 extern COLOR_MAP maincoltable;
 extern color palette[256];
 extern CCRegion ccDynamicRegion;
@@ -128,7 +128,7 @@ void Region_RunInteraction(ScriptRegion *ssr, int mood) {
 //=============================================================================
 
 void generate_light_table() {
-	if (game.color_depth == 1 && color_map == nullptr) {
+	if (_GP(game).color_depth == 1 && color_map == nullptr) {
 		create_light_table(&maincoltable, palette, 0, 0, 0, nullptr);
 		color_map = &maincoltable;
 	}
diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index 41ac25bceb..68236c76bc 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -79,7 +79,7 @@
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -87,7 +87,7 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern GameSetup usetup;
-extern GameSetupStruct game;
+
 extern GameState play;
 extern RoomStatus *croom;
 extern RoomStatus troom;    // used for non-saveable rooms, eg. intro
@@ -103,7 +103,7 @@ extern int done_es_error;
 extern int our_eip;
 extern Bitmap *walkareabackup, *walkable_areas_temp;
 extern ScriptObject scrObj[MAX_ROOM_OBJECTS];
-extern SpriteCache spriteset;
+
 extern int in_new_room, new_room_was;  // 1 in new room, 2 first time in new room, 3 loading saved game
 extern ScriptHotspot scrHotspot[MAX_ROOM_HOTSPOTS];
 extern int in_leaves_screen;
@@ -226,9 +226,9 @@ const char *Room_GetMessages(int index) {
 
 // Makes sure that room background and walk-behind mask are matching room size
 // in game resolution coordinates; in other words makes graphics appropriate
-// for display in the game.
+// for display in the _GP(game).
 void convert_room_background_to_game_res() {
-	if (!game.AllowRelativeRes() || !thisroom.IsRelativeRes())
+	if (!_GP(game).AllowRelativeRes() || !thisroom.IsRelativeRes())
 		return;
 
 	int bkg_width = thisroom.Width;
@@ -304,7 +304,7 @@ void unload_old_room() {
 		croom->interactionVariableValues[i] = thisroom.LocalVariables[i].Value;
 
 	// wipe the character cache when we change rooms
-	for (ff = 0; ff < game.numcharacters; ff++) {
+	for (ff = 0; ff < _GP(game).numcharacters; ff++) {
 		if (charcache[ff].inUse) {
 			delete charcache[ff].image;
 			charcache[ff].image = nullptr;
@@ -342,7 +342,7 @@ void unload_old_room() {
 	// clear the actsps buffers to save memory, since the
 	// objects/characters involved probably aren't on the
 	// new screen. this also ensures all cached data is flushed
-	for (ff = 0; ff < MAX_ROOM_OBJECTS + game.numcharacters; ff++) {
+	for (ff = 0; ff < MAX_ROOM_OBJECTS + _GP(game).numcharacters; ff++) {
 		delete actsps[ff];
 		actsps[ff] = nullptr;
 
@@ -362,7 +362,7 @@ void unload_old_room() {
 
 	// if Hide Player Character was ticked, restore it to visible
 	if (play.temporarily_turned_off_character >= 0) {
-		game.chars[play.temporarily_turned_off_character].on = 1;
+		_GP(game).chars[play.temporarily_turned_off_character].on = 1;
 		play.temporarily_turned_off_character = -1;
 	}
 
@@ -371,10 +371,10 @@ void unload_old_room() {
 // Convert all room objects to the data resolution (only if it's different from game resolution).
 // TODO: merge this into UpdateRoomData? or this is required for engine only?
 void convert_room_coordinates_to_data_res(RoomStruct *rstruc) {
-	if (game.GetDataUpscaleMult() == 1)
+	if (_GP(game).GetDataUpscaleMult() == 1)
 		return;
 
-	const int mul = game.GetDataUpscaleMult();
+	const int mul = _GP(game).GetDataUpscaleMult();
 	for (size_t i = 0; i < rstruc->ObjectCount; ++i) {
 		rstruc->Objects[i].X /= mul;
 		rstruc->Objects[i].Y /= mul;
@@ -404,16 +404,16 @@ extern int convert_16bit_bgr;
 
 void update_letterbox_mode() {
 	const Size real_room_sz = Size(data_to_game_coord(thisroom.Width), data_to_game_coord(thisroom.Height));
-	const Rect game_frame = RectWH(game.GetGameRes());
+	const Rect game_frame = RectWH(_GP(game).GetGameRes());
 	Rect new_main_view = game_frame;
 	// In the original engine the letterbox feature only allowed viewports of
 	// either 200 or 240 (400 and 480) pixels, if the room height was equal or greater than 200 (400).
 	// Also, the UI viewport should be matching room viewport in that case.
 	// NOTE: if "OPT_LETTERBOX" is false, altsize.Height = size.Height always.
 	const int viewport_height =
-	    real_room_sz.Height < game.GetLetterboxSize().Height ? real_room_sz.Height :
-	    (real_room_sz.Height >= game.GetLetterboxSize().Height && real_room_sz.Height < game.GetGameRes().Height) ? game.GetLetterboxSize().Height :
-	    game.GetGameRes().Height;
+	    real_room_sz.Height < _GP(game).GetLetterboxSize().Height ? real_room_sz.Height :
+	    (real_room_sz.Height >= _GP(game).GetLetterboxSize().Height && real_room_sz.Height < _GP(game).GetGameRes().Height) ? _GP(game).GetLetterboxSize().Height :
+	    _GP(game).GetGameRes().Height;
 	new_main_view.SetHeight(viewport_height);
 
 	play.SetMainViewport(CenterInRect(game_frame, new_main_view));
@@ -477,11 +477,11 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	// load the room from disk
 	our_eip = 200;
 	thisroom.GameID = NO_GAME_ID_IN_ROOM_FILE;
-	load_room(room_filename, &thisroom, game.IsLegacyHiRes(), game.SpriteInfos);
+	load_room(room_filename, &thisroom, _GP(game).IsLegacyHiRes(), _GP(game).SpriteInfos);
 
 	if ((thisroom.GameID != NO_GAME_ID_IN_ROOM_FILE) &&
-	        (thisroom.GameID != game.uniqueid)) {
-		quitprintf("!Unable to load '%s'. This room file is assigned to a different game.", room_filename.GetCStr());
+	        (thisroom.GameID != _GP(game).uniqueid)) {
+		quitprintf("!Unable to load '%s'. This room file is assigned to a different _GP(game).", room_filename.GetCStr());
 	}
 
 	convert_room_coordinates_to_data_res(&thisroom);
@@ -501,7 +501,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 
 	// do the palette
 	for (cc = 0; cc < 256; cc++) {
-		if (game.paluses[cc] == PAL_BACKGROUND)
+		if (_GP(game).paluses[cc] == PAL_BACKGROUND)
 			palette[cc] = thisroom.Palette[cc];
 		else {
 			// copy the gamewide colours into the room palette
@@ -519,7 +519,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 
 	our_eip = 202;
 	// Update game viewports
-	if (game.IsLegacyLetterbox())
+	if (_GP(game).IsLegacyLetterbox())
 		update_letterbox_mode();
 	SetMouseBounds(0, 0, 0, 0);
 
@@ -542,7 +542,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	redo_walkable_areas();
 	update_polled_stuff_if_runtime();
 
-	set_color_depth(game.GetColorDepth());
+	set_color_depth(_GP(game).GetColorDepth());
 	convert_room_background_to_game_res();
 	recache_walk_behinds();
 	update_polled_stuff_if_runtime();
@@ -702,22 +702,22 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 
 		// if a following character is still waiting to come into the
 		// previous room, force it out so that the timer resets
-		for (int ff = 0; ff < game.numcharacters; ff++) {
-			if ((game.chars[ff].following >= 0) && (game.chars[ff].room < 0)) {
-				if ((game.chars[ff].following == game.playercharacter) &&
+		for (int ff = 0; ff < _GP(game).numcharacters; ff++) {
+			if ((_GP(game).chars[ff].following >= 0) && (_GP(game).chars[ff].room < 0)) {
+				if ((_GP(game).chars[ff].following == _GP(game).playercharacter) &&
 				        (forchar->prevroom == newnum))
 					// the player went back to the previous room, so make sure
 					// the following character is still there
-					game.chars[ff].room = newnum;
+					_GP(game).chars[ff].room = newnum;
 				else
-					game.chars[ff].room = game.chars[game.chars[ff].following].room;
+					_GP(game).chars[ff].room = _GP(game).chars[_GP(game).chars[ff].following].room;
 			}
 		}
 
 		forchar->prevroom = forchar->room;
 		forchar->room = newnum;
 		// only stop moving if it's a new room, not a restore game
-		for (cc = 0; cc < game.numcharacters; cc++)
+		for (cc = 0; cc < _GP(game).numcharacters; cc++)
 			StopMoving(cc);
 
 	}
@@ -865,7 +865,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 			// remember which character we turned off, in case they
 			// use SetPlyaerChracter within this room (so we re-enable
 			// the correct character when leaving the room)
-			play.temporarily_turned_off_character = game.playercharacter;
+			play.temporarily_turned_off_character = _GP(game).playercharacter;
 		}
 		if (forchar->flags & CHF_FIXVIEW) ;
 		else if (thisroom.Options.PlayerView == 0) forchar->view = forchar->defview;
@@ -901,7 +901,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	// trash any input which they might have done while it was loading
 	ags_clear_input_buffer();
 	// no fade in, so set the palette immediately in case of 256-col sprites
-	if (game.color_depth > 1)
+	if (_GP(game).color_depth > 1)
 		setpal();
 
 	our_eip = 220;
@@ -909,7 +909,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	debug_script_log("Now in room %d", displayed_room);
 	guis_need_update = 1;
 	pl_run_plugin_hooks(AGSE_ENTERROOM, displayed_room);
-	//  MoveToWalkableArea(game.playercharacter);
+	//  MoveToWalkableArea(_GP(game).playercharacter);
 	//  MSS_CHECK_ALL_BLOCKS;
 }
 
@@ -936,7 +936,7 @@ void new_room(int newnum, CharacterInfo *forchar) {
 	in_leaves_screen = -1;
 
 	if ((playerchar->following >= 0) &&
-	        (game.chars[playerchar->following].room != newnum)) {
+	        (_GP(game).chars[playerchar->following].room != newnum)) {
 		// the player character is following another character,
 		// who is not in the new room. therefore, abort the follow
 		playerchar->following = -1;
@@ -948,10 +948,10 @@ void new_room(int newnum, CharacterInfo *forchar) {
 
 	if (_G(psp_clear_cache_on_room_change)) {
 		// Delete all cached sprites
-		spriteset.DisposeAll();
+		_GP(spriteset).DisposeAll();
 
 		// Delete all gui background images
-		for (int i = 0; i < game.numgui; i++) {
+		for (int i = 0; i < _GP(game).numgui; i++) {
 			delete guibg[i];
 			guibg[i] = nullptr;
 
@@ -992,7 +992,7 @@ void check_new_room() {
 		evh.data1 = EVB_ROOM;
 		evh.data2 = 0;
 		evh.data3 = 5;
-		evh.player = game.playercharacter;
+		evh.player = _GP(game).playercharacter;
 		// make sure that any script calls don't re-call enters screen
 		int newroom_was = in_new_room;
 		in_new_room = 0;
@@ -1035,7 +1035,7 @@ void on_background_frame_change() {
 
 	// hi-colour, update the palette. It won't have an immediate effect
 	// but will be drawn properly when the screen fades in
-	if (game.color_depth > 1)
+	if (_GP(game).color_depth > 1)
 		setpal();
 
 	if (in_enters_screen)
@@ -1047,7 +1047,7 @@ void on_background_frame_change() {
 
 	// 256-colours, tell it to update the palette (will actually be done as
 	// close as possible to the screen update to prevent flicker problem)
-	if (game.color_depth == 1)
+	if (_GP(game).color_depth == 1)
 		bg_just_changed = 1;
 }
 
@@ -1058,24 +1058,24 @@ void croom_ptr_clear() {
 
 
 AGS_INLINE int room_to_mask_coord(int coord) {
-	return coord * game.GetDataUpscaleMult() / thisroom.MaskResolution;
+	return coord * _GP(game).GetDataUpscaleMult() / thisroom.MaskResolution;
 }
 
 AGS_INLINE int mask_to_room_coord(int coord) {
-	return coord * thisroom.MaskResolution / game.GetDataUpscaleMult();
+	return coord * thisroom.MaskResolution / _GP(game).GetDataUpscaleMult();
 }
 
 void convert_move_path_to_room_resolution(MoveList *ml) {
-	if ((game.options[OPT_WALKSPEEDABSOLUTE] != 0) && game.GetDataUpscaleMult() > 1) {
+	if ((_GP(game).options[OPT_WALKSPEEDABSOLUTE] != 0) && _GP(game).GetDataUpscaleMult() > 1) {
 		// Speeds are independent from MaskResolution
 		for (int i = 0; i < ml->numstage; i++) {
 			// ...so they are not multiplied by MaskResolution factor when converted to room coords
-			ml->xpermove[i] = ml->xpermove[i] / game.GetDataUpscaleMult();
-			ml->ypermove[i] = ml->ypermove[i] / game.GetDataUpscaleMult();
+			ml->xpermove[i] = ml->xpermove[i] / _GP(game).GetDataUpscaleMult();
+			ml->ypermove[i] = ml->ypermove[i] / _GP(game).GetDataUpscaleMult();
 		}
 	}
 
-	if (thisroom.MaskResolution == game.GetDataUpscaleMult())
+	if (thisroom.MaskResolution == _GP(game).GetDataUpscaleMult())
 		return;
 
 	ml->fromx = mask_to_room_coord(ml->fromx);
@@ -1089,7 +1089,7 @@ void convert_move_path_to_room_resolution(MoveList *ml) {
 		ml->pos[i] = ((int)highPart << 16) | (lowPart & 0x0000ffff);
 	}
 
-	if (game.options[OPT_WALKSPEEDABSOLUTE] == 0) {
+	if (_GP(game).options[OPT_WALKSPEEDABSOLUTE] == 0) {
 		// Speeds are scaling with MaskResolution
 		for (int i = 0; i < ml->numstage; i++) {
 			ml->xpermove[i] = mask_to_room_coord(ml->xpermove[i]);
diff --git a/engines/ags/engine/ac/roomobject.cpp b/engines/ags/engine/ac/roomobject.cpp
index cc1ed9fbe4..d6e8caec64 100644
--- a/engines/ags/engine/ac/roomobject.cpp
+++ b/engines/ags/engine/ac/roomobject.cpp
@@ -29,6 +29,7 @@
 #include "ags/engine/ac/viewframe.h"
 #include "ags/engine/main/update.h"
 #include "ags/shared/util/stream.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -36,7 +37,7 @@ using AGS::Shared::Stream;
 
 extern ViewStruct *views;
 extern GameState play;
-extern GameSetupStruct game;
+
 
 RoomObject::RoomObject() {
 	x = y = 0;
@@ -59,12 +60,12 @@ RoomObject::RoomObject() {
 
 int RoomObject::get_width() {
 	if (last_width == 0)
-		return game.SpriteInfos[num].Width;
+		return _GP(game).SpriteInfos[num].Width;
 	return last_width;
 }
 int RoomObject::get_height() {
 	if (last_height == 0)
-		return game.SpriteInfos[num].Height;
+		return _GP(game).SpriteInfos[num].Height;
 	return last_height;
 }
 int RoomObject::get_baseline() {
diff --git a/engines/ags/engine/ac/screen.cpp b/engines/ags/engine/ac/screen.cpp
index 06fc83fe55..92c862576c 100644
--- a/engines/ags/engine/ac/screen.cpp
+++ b/engines/ags/engine/ac/screen.cpp
@@ -35,19 +35,19 @@
 #include "ags/plugins/plugin_engine.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/gfx/graphicsdriver.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
 extern GameState play;
 extern IGraphicsDriver *gfxDriver;
 extern AGSPlatformDriver *platform;
 
 void my_fade_in(PALETTE p, int speed) {
-	if (game.color_depth > 1) {
+	if (_GP(game).color_depth > 1) {
 		set_palette(p);
 
 		play.screen_is_faded_out = 0;
@@ -116,11 +116,11 @@ IDriverDependantBitmap *prepare_screen_for_transition_in() {
 //=============================================================================
 
 int Screen_GetScreenWidth() {
-	return game.GetGameRes().Width;
+	return _GP(game).GetGameRes().Width;
 }
 
 int Screen_GetScreenHeight() {
-	return game.GetGameRes().Height;
+	return _GP(game).GetGameRes().Height;
 }
 
 bool Screen_GetAutoSizeViewport() {
diff --git a/engines/ags/engine/ac/speech.cpp b/engines/ags/engine/ac/speech.cpp
index 8164c12362..10a1203f8e 100644
--- a/engines/ags/engine/ac/speech.cpp
+++ b/engines/ags/engine/ac/speech.cpp
@@ -24,7 +24,6 @@
 #include "ags/engine/ac/runtime_defines.h"
 #include "ags/engine/ac/speech.h"
 #include "ags/engine/debugging/debug_log.h"
-
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/ac/gamestate.h"
 #include "ags/engine/ac/global_audio.h"
@@ -32,6 +31,7 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -86,7 +86,7 @@ SkipSpeechStyle internal_skip_speech_to_user(int internal_val) {
 //
 //=============================================================================
 
-extern GameSetupStruct game;
+
 extern GameState play;
 
 RuntimeScriptValue Sc_Speech_GetAnimationStopTimeMargin(const RuntimeScriptValue *params, int32_t param_count) {
@@ -118,7 +118,7 @@ RuntimeScriptValue Sc_Speech_GetGlobalSpeechAnimationDelay(const RuntimeScriptVa
 }
 
 RuntimeScriptValue Sc_Speech_SetGlobalSpeechAnimationDelay(const RuntimeScriptValue *params, int32_t param_count) {
-	if (game.options[OPT_GLOBALTALKANIMSPD] == 0) {
+	if (_GP(game).options[OPT_GLOBALTALKANIMSPD] == 0) {
 		debug_script_warn("Speech.GlobalSpeechAnimationDelay cannot be set when global speech animation speed is not enabled; set Speech.UseGlobalSpeechAnimationDelay first!");
 		return RuntimeScriptValue();
 	}
@@ -142,7 +142,7 @@ RuntimeScriptValue Sc_Speech_SetPortraitY(const RuntimeScriptValue *params, int3
 }
 
 RuntimeScriptValue Sc_Speech_GetStyle(const RuntimeScriptValue *params, int32_t param_count) {
-	API_VARGET_INT(game.options[OPT_SPEECHTYPE]);
+	API_VARGET_INT(_GP(game).options[OPT_SPEECHTYPE]);
 }
 
 extern RuntimeScriptValue Sc_SetSpeechStyle(const RuntimeScriptValue *params, int32_t param_count);
@@ -178,11 +178,11 @@ RuntimeScriptValue Sc_Speech_SetTextAlignment(const RuntimeScriptValue *params,
 }
 
 RuntimeScriptValue Sc_Speech_GetUseGlobalSpeechAnimationDelay(const RuntimeScriptValue *params, int32_t param_count) {
-	API_VARGET_INT(game.options[OPT_GLOBALTALKANIMSPD]);
+	API_VARGET_INT(_GP(game).options[OPT_GLOBALTALKANIMSPD]);
 }
 
 RuntimeScriptValue Sc_Speech_SetUseGlobalSpeechAnimationDelay(const RuntimeScriptValue *params, int32_t param_count) {
-	API_VARSET_PINT(game.options[OPT_GLOBALTALKANIMSPD]);
+	API_VARSET_PINT(_GP(game).options[OPT_GLOBALTALKANIMSPD]);
 }
 
 RuntimeScriptValue Sc_Speech_GetVoiceMode(const RuntimeScriptValue *params, int32_t param_count) {
diff --git a/engines/ags/engine/ac/sprite.cpp b/engines/ags/engine/ac/sprite.cpp
index ccecda46bc..3d46f0fac6 100644
--- a/engines/ags/engine/ac/sprite.cpp
+++ b/engines/ags/engine/ac/sprite.cpp
@@ -31,14 +31,14 @@
 #include "ags/shared/ac/spritecache.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/gfx/graphicsdriver.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
-extern SpriteCache spriteset;
+
 extern int our_eip, eip_guinum, eip_guiobj;
 extern color palette[256];
 extern IGraphicsDriver *gfxDriver;
@@ -47,8 +47,8 @@ extern AGSPlatformDriver *platform;
 void get_new_size_for_sprite(int ee, int ww, int hh, int &newwid, int &newhit) {
 	newwid = ww;
 	newhit = hh;
-	const SpriteInfo &spinfo = game.SpriteInfos[ee];
-	if (!game.AllowRelativeRes() || !spinfo.IsRelativeRes())
+	const SpriteInfo &spinfo = _GP(game).SpriteInfos[ee];
+	if (!_GP(game).AllowRelativeRes() || !spinfo.IsRelativeRes())
 		return;
 	ctx_data_to_game_size(newwid, newhit, spinfo.IsLegacyHiRes());
 }
@@ -70,7 +70,7 @@ void set_rgb_mask_using_alpha_channel(Bitmap *image) {
 
 // from is a 32-bit RGBA image, to is a 15/16/24-bit destination image
 Bitmap *remove_alpha_channel(Bitmap *from) {
-	const int game_cd = game.GetColorDepth();
+	const int game_cd = _GP(game).GetColorDepth();
 	Bitmap *to = BitmapHelper::CreateBitmap(from->GetWidth(), from->GetHeight(), game_cd);
 	const int maskcol = to->GetMaskColor();
 	int y, x;
@@ -126,27 +126,27 @@ Bitmap *tmpdbl, *curspr;
 int newwid, newhit;
 void initialize_sprite(int ee) {
 
-	if ((ee < 0) || (ee > spriteset.GetSpriteSlotCount()))
+	if ((ee < 0) || (ee > _GP(spriteset).GetSpriteSlotCount()))
 		quit("initialize_sprite: invalid sprite number");
 
-	if ((spriteset[ee] == nullptr) && (ee > 0)) {
+	if ((_GP(spriteset)[ee] == nullptr) && (ee > 0)) {
 		// replace empty sprites with blue cups, to avoid crashes
-		spriteset.RemapSpriteToSprite0(ee);
-	} else if (spriteset[ee] == nullptr) {
-		game.SpriteInfos[ee].Width = 0;
-		game.SpriteInfos[ee].Height = 0;
+		_GP(spriteset).RemapSpriteToSprite0(ee);
+	} else if (_GP(spriteset)[ee] == nullptr) {
+		_GP(game).SpriteInfos[ee].Width = 0;
+		_GP(game).SpriteInfos[ee].Height = 0;
 	} else {
 		// stretch sprites to correct resolution
 		int oldeip = our_eip;
 		our_eip = 4300;
 
-		if (game.SpriteInfos[ee].Flags & SPF_HADALPHACHANNEL) {
+		if (_GP(game).SpriteInfos[ee].Flags & SPF_HADALPHACHANNEL) {
 			// we stripped the alpha channel out last time, put
 			// it back so that we can remove it properly again
-			game.SpriteInfos[ee].Flags |= SPF_ALPHACHANNEL;
+			_GP(game).SpriteInfos[ee].Flags |= SPF_ALPHACHANNEL;
 		}
 
-		curspr = spriteset[ee];
+		curspr = _GP(spriteset)[ee];
 		get_new_size_for_sprite(ee, curspr->GetWidth(), curspr->GetHeight(), newwid, newhit);
 
 		eip_guinum = ee;
@@ -162,19 +162,19 @@ void initialize_sprite(int ee) {
 			curspr->Release();
 			tmpdbl->Release();
 			delete curspr;
-			spriteset.SubstituteBitmap(ee, tmpdbl);
+			_GP(spriteset).SubstituteBitmap(ee, tmpdbl);
 		}
 
-		game.SpriteInfos[ee].Width = spriteset[ee]->GetWidth();
-		game.SpriteInfos[ee].Height = spriteset[ee]->GetHeight();
+		_GP(game).SpriteInfos[ee].Width = _GP(spriteset)[ee]->GetWidth();
+		_GP(game).SpriteInfos[ee].Height = _GP(spriteset)[ee]->GetHeight();
 
-		spriteset.SubstituteBitmap(ee, PrepareSpriteForUse(spriteset[ee], (game.SpriteInfos[ee].Flags & SPF_ALPHACHANNEL) != 0));
+		_GP(spriteset).SubstituteBitmap(ee, PrepareSpriteForUse(_GP(spriteset)[ee], (_GP(game).SpriteInfos[ee].Flags & SPF_ALPHACHANNEL) != 0));
 
-		if (game.GetColorDepth() < 32) {
-			game.SpriteInfos[ee].Flags &= ~SPF_ALPHACHANNEL;
+		if (_GP(game).GetColorDepth() < 32) {
+			_GP(game).SpriteInfos[ee].Flags &= ~SPF_ALPHACHANNEL;
 			// save the fact that it had one for the next time this
 			// is re-loaded from disk
-			game.SpriteInfos[ee].Flags |= SPF_HADALPHACHANNEL;
+			_GP(game).SpriteInfos[ee].Flags |= SPF_HADALPHACHANNEL;
 		}
 
 		pl_run_plugin_hooks(AGSE_SPRITELOAD, ee);
diff --git a/engines/ags/engine/ac/statobj/agsstaticobject.cpp b/engines/ags/engine/ac/statobj/agsstaticobject.cpp
index 4cc1f476cc..5e7ff1e6c2 100644
--- a/engines/ags/engine/ac/statobj/agsstaticobject.cpp
+++ b/engines/ags/engine/ac/statobj/agsstaticobject.cpp
@@ -24,6 +24,7 @@
 #include "ags/engine/ac/statobj/agsstaticobject.h"
 #include "ags/engine/ac/game.h"
 #include "ags/engine/ac/gamestate.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -77,10 +78,10 @@ void AGSStaticObject::WriteFloat(const char *address, intptr_t offset, float val
 
 void StaticGame::WriteInt32(const char *address, intptr_t offset, int32_t val) {
 	if (offset == 4 * sizeof(int32_t)) {
-		// game.debug_mode
+		// _GP(game).debug_mode
 		set_debug_mode(val != 0);
 	} else if (offset == 99 * sizeof(int32_t) || offset == 112 * sizeof(int32_t)) {
-		// game.text_align, game.speech_text_align
+		// _GP(game).text_align, _GP(game).speech_text_align
 		*(int32_t *)(const_cast<char *>(address) + offset) = ReadScriptAlignment(val);
 	} else {
 		*(int32_t *)(const_cast<char *>(address) + offset) = val;
diff --git a/engines/ags/engine/ac/string.cpp b/engines/ags/engine/ac/string.cpp
index d679db77ad..75dda91c4b 100644
--- a/engines/ags/engine/ac/string.cpp
+++ b/engines/ags/engine/ac/string.cpp
@@ -33,15 +33,14 @@
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/engine/script/runtimescriptvalue.h"
 #include "ags/shared/util/string_compat.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/math.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
 extern GameState play;
 extern int longestline;
 extern ScriptString myScriptStringImpl;
@@ -255,7 +254,7 @@ size_t break_up_text_into_lines(const char *todis, SplitLines &lines, int wii, i
 
 	// Right-to-left just means reverse the text then
 	// write it as normal
-	if (game.options[OPT_RIGHTLEFTWRITE])
+	if (_GP(game).options[OPT_RIGHTLEFTWRITE])
 		for (size_t rr = 0; rr < lines.Count(); rr++) {
 			lines[rr].Reverse();
 			line_length = wgettextwidth_compensate(lines[rr], fonnt);
@@ -273,8 +272,8 @@ size_t break_up_text_into_lines(const char *todis, SplitLines &lines, int wii, i
 int MAXSTRLEN = MAX_MAXSTRLEN;
 void check_strlen(char *ptt) {
 	MAXSTRLEN = MAX_MAXSTRLEN;
-	const byte *charstart = (const byte *)&game.chars[0];
-	const byte *charend = charstart + sizeof(CharacterInfo) * game.numcharacters;
+	const byte *charstart = (const byte *)&_GP(game).chars[0];
+	const byte *charend = charstart + sizeof(CharacterInfo) * _GP(game).numcharacters;
 	if (((const byte *)&ptt[0] >= charstart) && ((const byte *)&ptt[0] <= charend))
 		MAXSTRLEN = 30;
 }
diff --git a/engines/ags/engine/ac/sys_events.cpp b/engines/ags/engine/ac/sys_events.cpp
index 2f8b9c9795..0239f064e2 100644
--- a/engines/ags/engine/ac/sys_events.cpp
+++ b/engines/ags/engine/ac/sys_events.cpp
@@ -30,6 +30,7 @@
 #include "ags/engine/device/mousew32.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
 #include "ags/engine/ac/timer.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 #include "ags/events.h"
 
@@ -38,7 +39,7 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern GameState play;
 
 extern volatile unsigned long globalTimerCounter;
@@ -89,7 +90,7 @@ void ags_domouse(int what) {
 
 int ags_check_mouse_wheel() {
 	int result = 0;
-	if ((mouse_z != mouse_z_was) && (game.options[OPT_MOUSEWHEEL] != 0)) {
+	if ((mouse_z != mouse_z_was) && (_GP(game).options[OPT_MOUSEWHEEL] != 0)) {
 		if (mouse_z > mouse_z_was)
 			result = 1;
 		else
diff --git a/engines/ags/engine/ac/system.cpp b/engines/ags/engine/ac/system.cpp
index a390118928..025464d840 100644
--- a/engines/ags/engine/ac/system.cpp
+++ b/engines/ags/engine/ac/system.cpp
@@ -44,7 +44,7 @@
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/events.h"
 
 namespace AGS3 {
@@ -52,7 +52,7 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern GameSetup usetup;
 extern GameState play;
 extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
@@ -95,11 +95,11 @@ int System_GetOS() {
 // compatibility.
 //
 int System_GetScreenWidth() {
-	return game.GetGameRes().Width;
+	return _GP(game).GetGameRes().Width;
 }
 
 int System_GetScreenHeight() {
-	return game.GetGameRes().Height;
+	return _GP(game).GetGameRes().Height;
 }
 
 int System_GetViewportHeight() {
diff --git a/engines/ags/engine/ac/textbox.cpp b/engines/ags/engine/ac/textbox.cpp
index c8cea8558e..674d7adbb6 100644
--- a/engines/ags/engine/ac/textbox.cpp
+++ b/engines/ags/engine/ac/textbox.cpp
@@ -20,22 +20,18 @@
  *
  */
 
-//include <string.h>
 #include "ags/engine/ac/textbox.h"
 #include "ags/shared/ac/common.h"
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/ac/string.h"
-
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
 #include "ags/engine/ac/dynobj/scriptstring.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
-
-
 // ** TEXT BOX FUNCTIONS
 
 const char *TextBox_GetText_New(GUITextBox *texbox) {
@@ -69,7 +65,7 @@ int TextBox_GetFont(GUITextBox *guit) {
 }
 
 void TextBox_SetFont(GUITextBox *guit, int fontnum) {
-	if ((fontnum < 0) || (fontnum >= game.numfonts))
+	if ((fontnum < 0) || (fontnum >= _GP(game).numfonts))
 		quit("!SetTextBoxFont: invalid font number.");
 
 	if (guit->Font != fontnum) {
diff --git a/engines/ags/engine/ac/translation.cpp b/engines/ags/engine/ac/translation.cpp
index 7f4612b776..65a662975f 100644
--- a/engines/ags/engine/ac/translation.cpp
+++ b/engines/ags/engine/ac/translation.cpp
@@ -20,7 +20,6 @@
  *
  */
 
-//include <cstdio>
 #include "ags/engine/ac/asset_helper.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/gamesetup.h"
@@ -35,13 +34,14 @@
 #include "ags/shared/util/misc.h"
 #include "ags/shared/util/stream.h"
 #include "ags/shared/core/assetmanager.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 
 extern GameSetup usetup;
-extern GameSetupStruct game;
+
 extern GameState play;
 extern char transFileName[MAX_PATH];
 
@@ -136,8 +136,8 @@ bool parse_translation(Stream *language_file, String &parse_error) {
 			char wasgamename[100];
 			uidfrom = language_file->ReadInt32();
 			read_string_decrypt(language_file, wasgamename, sizeof(wasgamename));
-			if ((uidfrom != game.uniqueid) || (strcmp(wasgamename, game.gamename) != 0)) {
-				parse_error.Format("The translation file is not compatible with this game. The translation is designed for '%s'.",
+			if ((uidfrom != _GP(game).uniqueid) || (strcmp(wasgamename, _GP(game).gamename) != 0)) {
+				parse_error.Format("The translation file is not compatible with this _GP(game). The translation is designed for '%s'.",
 					wasgamename);
 				return false;
 			}
@@ -155,10 +155,10 @@ bool parse_translation(Stream *language_file, String &parse_error) {
 			// text direction
 			if (temp == 1) {
 				play.text_align = kHAlignLeft;
-				game.options[OPT_RIGHTLEFTWRITE] = 0;
+				_GP(game).options[OPT_RIGHTLEFTWRITE] = 0;
 			} else if (temp == 2) {
 				play.text_align = kHAlignRight;
-				game.options[OPT_RIGHTLEFTWRITE] = 1;
+				_GP(game).options[OPT_RIGHTLEFTWRITE] = 1;
 			}
 		} else {
 			parse_error.Format("Unknown block type in translation file (%d).", blockType);
diff --git a/engines/ags/engine/ac/viewframe.cpp b/engines/ags/engine/ac/viewframe.cpp
index 6faa57becc..144d395a56 100644
--- a/engines/ags/engine/ac/viewframe.cpp
+++ b/engines/ags/engine/ac/viewframe.cpp
@@ -34,15 +34,16 @@
 #include "ags/shared/debugging/out.h"
 #include "ags/engine/script/script_api.h"
 #include "ags/engine/script/script_runtime.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using AGS::Shared::Bitmap;
 using AGS::Shared::Graphics;
 
-extern GameSetupStruct game;
+
 extern ViewStruct *views;
-extern SpriteCache spriteset;
+
 extern CCAudioClip ccDynamicAudioClip;
 
 
@@ -65,7 +66,7 @@ ScriptAudioClip *ViewFrame_GetLinkedAudio(ScriptViewFrame *svf) {
 	if (soundIndex < 0)
 		return nullptr;
 
-	return &game.audioClips[soundIndex];
+	return &_GP(game).audioClips[soundIndex];
 }
 
 void ViewFrame_SetLinkedAudio(ScriptViewFrame *svf, ScriptAudioClip *clip) {
@@ -86,11 +87,11 @@ void ViewFrame_SetSound(ScriptViewFrame *svf, int newSound) {
 		views[svf->view].loops[svf->loop].frames[svf->frame].sound = -1;
 	} else {
 		// convert sound number to audio clip
-		ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(game, false, newSound);
+		ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(_GP(game), false, newSound);
 		if (clip == nullptr)
 			quitprintf("!SetFrameSound: audio clip aSound%d not found", newSound);
 
-		views[svf->view].loops[svf->loop].frames[svf->frame].sound = clip->id + (game.IsLegacyAudioSystem() ? 0x10000000 : 0);
+		views[svf->view].loops[svf->loop].frames[svf->frame].sound = clip->id + (_GP(game).IsLegacyAudioSystem() ? 0x10000000 : 0);
 	}
 }
 
@@ -118,7 +119,7 @@ void precache_view(int view) {
 
 	for (int i = 0; i < views[view].numLoops; i++) {
 		for (int j = 0; j < views[view].loops[i].numFrames; j++)
-			spriteset.Precache(views[view].loops[i].frames[j].pic);
+			_GP(spriteset).Precache(views[view].loops[i].frames[j].pic);
 	}
 }
 
@@ -126,10 +127,10 @@ void precache_view(int view) {
 // to play a sound or whatever
 void CheckViewFrame(int view, int loop, int frame, int sound_volume) {
 	ScriptAudioChannel *channel = nullptr;
-	if (game.IsLegacyAudioSystem()) {
+	if (_GP(game).IsLegacyAudioSystem()) {
 		if (views[view].loops[loop].frames[frame].sound > 0) {
 			if (views[view].loops[loop].frames[frame].sound < 0x10000000) {
-				ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(game, false, views[view].loops[loop].frames[frame].sound);
+				ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(_GP(game), false, views[view].loops[loop].frames[frame].sound);
 				if (clip)
 					views[view].loops[loop].frames[frame].sound = clip->id + 0x10000000;
 				else {
@@ -158,21 +159,21 @@ void CheckViewFrame(int view, int loop, int frame, int sound_volume) {
 void DrawViewFrame(Bitmap *ds, const ViewFrame *vframe, int x, int y, bool alpha_blend) {
 	// NOTE: DrawViewFrame supports alpha blending only since OPT_SPRITEALPHA;
 	// this is why there's no sense in blending if it's not set (will do no good anyway).
-	if (alpha_blend && game.options[OPT_SPRITEALPHA] == kSpriteAlphaRender_Proper) {
-		Bitmap *vf_bmp = spriteset[vframe->pic];
+	if (alpha_blend && _GP(game).options[OPT_SPRITEALPHA] == kSpriteAlphaRender_Proper) {
+		Bitmap *vf_bmp = _GP(spriteset)[vframe->pic];
 		Bitmap *src = vf_bmp;
 		if (vframe->flags & VFLG_FLIPSPRITE) {
 			src = new Bitmap(vf_bmp->GetWidth(), vf_bmp->GetHeight(), vf_bmp->GetColorDepth());
 			src->FlipBlt(vf_bmp, 0, 0, Shared::kBitmap_HFlip);
 		}
-		draw_sprite_support_alpha(ds, true, x, y, src, (game.SpriteInfos[vframe->pic].Flags & SPF_ALPHACHANNEL) != 0);
+		draw_sprite_support_alpha(ds, true, x, y, src, (_GP(game).SpriteInfos[vframe->pic].Flags & SPF_ALPHACHANNEL) != 0);
 		if (src != vf_bmp)
 			delete src;
 	} else {
 		if (vframe->flags & VFLG_FLIPSPRITE)
-			ds->FlipBlt(spriteset[vframe->pic], x, y, Shared::kBitmap_HFlip);
+			ds->FlipBlt(_GP(spriteset)[vframe->pic], x, y, Shared::kBitmap_HFlip);
 		else
-			ds->Blit(spriteset[vframe->pic], x, y, Shared::kBitmap_Transparency);
+			ds->Blit(_GP(spriteset)[vframe->pic], x, y, Shared::kBitmap_Transparency);
 	}
 }
 
diff --git a/engines/ags/engine/ac/walkablearea.cpp b/engines/ags/engine/ac/walkablearea.cpp
index f8a585a9bc..e96bd93170 100644
--- a/engines/ags/engine/ac/walkablearea.cpp
+++ b/engines/ags/engine/ac/walkablearea.cpp
@@ -32,6 +32,7 @@
 #include "ags/engine/ac/walkablearea.h"
 #include "ags/shared/game/roomstruct.h"
 #include "ags/shared/gfx/bitmap.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -39,7 +40,7 @@ using namespace AGS::Shared;
 
 extern RoomStruct thisroom;
 extern GameState play;
-extern GameSetupStruct game;
+
 extern int displayed_room;
 extern RoomStatus *croom;
 extern RoomObject *objs;
@@ -109,8 +110,8 @@ int get_area_scaling(int onarea, int xx, int yy) {
 }
 
 void scale_sprite_size(int sppic, int zoom_level, int *newwidth, int *newheight) {
-	newwidth[0] = (game.SpriteInfos[sppic].Width * zoom_level) / 100;
-	newheight[0] = (game.SpriteInfos[sppic].Height * zoom_level) / 100;
+	newwidth[0] = (_GP(game).SpriteInfos[sppic].Width * zoom_level) / 100;
+	newheight[0] = (_GP(game).SpriteInfos[sppic].Height * zoom_level) / 100;
 	if (newwidth[0] < 1)
 		newwidth[0] = 1;
 	if (newheight[0] < 1)
@@ -149,22 +150,22 @@ Bitmap *prepare_walkable_areas(int sourceChar) {
 	walkable_areas_temp->Blit(thisroom.WalkAreaMask.get(), 0, 0, 0, 0, thisroom.WalkAreaMask->GetWidth(), thisroom.WalkAreaMask->GetHeight());
 	// if the character who's moving doesn't Bitmap *, don't bother checking
 	if (sourceChar < 0);
-	else if (game.chars[sourceChar].flags & CHF_NOBLOCKING)
+	else if (_GP(game).chars[sourceChar].flags & CHF_NOBLOCKING)
 		return walkable_areas_temp;
 
 	int ww;
 	// for each character in the current room, make the area under
 	// them unwalkable
-	for (ww = 0; ww < game.numcharacters; ww++) {
-		if (game.chars[ww].on != 1) continue;
-		if (game.chars[ww].room != displayed_room) continue;
+	for (ww = 0; ww < _GP(game).numcharacters; ww++) {
+		if (_GP(game).chars[ww].on != 1) continue;
+		if (_GP(game).chars[ww].room != displayed_room) continue;
 		if (ww == sourceChar) continue;
-		if (game.chars[ww].flags & CHF_NOBLOCKING) continue;
-		if (room_to_mask_coord(game.chars[ww].y) >= walkable_areas_temp->GetHeight()) continue;
-		if (room_to_mask_coord(game.chars[ww].x) >= walkable_areas_temp->GetWidth()) continue;
-		if ((game.chars[ww].y < 0) || (game.chars[ww].x < 0)) continue;
+		if (_GP(game).chars[ww].flags & CHF_NOBLOCKING) continue;
+		if (room_to_mask_coord(_GP(game).chars[ww].y) >= walkable_areas_temp->GetHeight()) continue;
+		if (room_to_mask_coord(_GP(game).chars[ww].x) >= walkable_areas_temp->GetWidth()) continue;
+		if ((_GP(game).chars[ww].y < 0) || (_GP(game).chars[ww].x < 0)) continue;
 
-		CharacterInfo *char1 = &game.chars[ww];
+		CharacterInfo *char1 = &_GP(game).chars[ww];
 		int cwidth, fromx;
 
 		if (is_char_on_another(sourceChar, ww, &fromx, &cwidth))
@@ -191,7 +192,7 @@ Bitmap *prepare_walkable_areas(int sourceChar) {
 		// if the character is currently standing on the object, ignore
 		// it so as to allow him to escape
 		if ((sourceChar >= 0) &&
-			(is_point_in_rect(game.chars[sourceChar].x, game.chars[sourceChar].y,
+			(is_point_in_rect(_GP(game).chars[sourceChar].x, _GP(game).chars[sourceChar].y,
 				x1, y1, x1 + width, y2)))
 			continue;
 
@@ -238,7 +239,7 @@ int get_walkable_area_at_location(int xx, int yy) {
 }
 
 int get_walkable_area_at_character(int charnum) {
-	CharacterInfo *chin = &game.chars[charnum];
+	CharacterInfo *chin = &_GP(game).chars[charnum];
 	return get_walkable_area_at_location(chin->x, chin->y);
 }
 
diff --git a/engines/ags/engine/debugging/debug.cpp b/engines/ags/engine/debugging/debug.cpp
index 92d9eea7fa..37f11af862 100644
--- a/engines/ags/engine/debugging/debug.cpp
+++ b/engines/ags/engine/debugging/debug.cpp
@@ -44,7 +44,7 @@
 #include "ags/shared/script/cc_error.h"
 #include "ags/shared/util/string_utils.h"
 #include "ags/shared/util/textstreamwriter.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/events.h"
 
 #if AGS_PLATFORM_OS_WINDOWS
@@ -60,7 +60,7 @@ extern char check_dynamic_sprites_at_exit;
 extern int displayed_room;
 extern RoomStruct thisroom;
 extern char pexbuf[STD_BUFFER_SIZE];
-extern GameSetupStruct game;
+
 
 #if AGS_PLATFORM_OS_WINDOWS
 
@@ -245,7 +245,7 @@ void apply_debug_config(const ConfigTree &cfg) {
 		});
 
 	// Init game console if the game was compiled in Debug mode
-	if (game.options[OPT_DEBUGMODE] != 0) {
+	if (_GP(game).options[OPT_DEBUGMODE] != 0) {
 		apply_log_config(cfg, OutputGameConsoleID,
 			/* defaults */
 			true, {
@@ -258,7 +258,7 @@ void apply_debug_config(const ConfigTree &cfg) {
 
 	// If the game was compiled in Debug mode *and* there's no regular file log,
 	// then open "warnings.log" for printing script warnings.
-	if (game.options[OPT_DEBUGMODE] != 0 && !DebugLogFile) {
+	if (_GP(game).options[OPT_DEBUGMODE] != 0 && !DebugLogFile) {
 		auto dbgout = create_log_output(OutputFileID, "warnings.log", LogFile::kLogFile_OverwriteAtFirstMessage);
 		if (dbgout) {
 			dbgout->SetGroupFilter(kDbgGroup_Game, kDbgMsg_Warn);
diff --git a/engines/ags/engine/device/mousew32.cpp b/engines/ags/engine/device/mousew32.cpp
index ed4497d51d..eeac9025b8 100644
--- a/engines/ags/engine/device/mousew32.cpp
+++ b/engines/ags/engine/device/mousew32.cpp
@@ -56,7 +56,7 @@
 #include "ags/engine/main/graphics_mode.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
 #include "ags/shared/util/math.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #if AGS_SIMULATE_RIGHT_CLICK
 #include "ags/shared/ac/sys_events.h" // j for ags_iskeypressed
 #endif
diff --git a/engines/ags/engine/font/fonts_engine.cpp b/engines/ags/engine/font/fonts_engine.cpp
index cd608b7a97..5e7c3871ad 100644
--- a/engines/ags/engine/font/fonts_engine.cpp
+++ b/engines/ags/engine/font/fonts_engine.cpp
@@ -32,7 +32,7 @@
 namespace AGS3 {
 
 extern int our_eip;
-extern GameSetupStruct game;
+
 
 //=============================================================================
 // Engine-specific implementation split out of acfonts.cpp
diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index 7f33733c53..f6c2938cba 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -50,13 +50,14 @@
 #include "ags/engine/script/script_runtime.h"
 #include "ags/shared/util/string_utils.h"
 #include "ags/engine/media/audio/audio_system.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace Shared;
 using namespace Engine;
 
-extern GameSetupStruct game;
+
 extern int actSpsCount;
 extern Bitmap **actsps;
 extern IDriverDependantBitmap **actspsbmp;
@@ -121,7 +122,7 @@ String GetGameInitErrorText(GameInitErrorType err) {
 	case kGameInitErr_NoError:
 		return "No error.";
 	case kGameInitErr_NoFonts:
-		return "No fonts specified to be used in this game.";
+		return "No fonts specified to be used in this _GP(game).";
 	case kGameInitErr_TooManyAudioTypes:
 		return "Too many audio types for this engine to handle.";
 	case kGameInitErr_EntityInitFail:
@@ -143,51 +144,51 @@ void InitAndRegisterAudioObjects() {
 		ccRegisterManagedObject(&scrAudioChannel[i], &ccDynamicAudio);
 	}
 
-	for (size_t i = 0; i < game.audioClips.size(); ++i) {
+	for (size_t i = 0; i < _GP(game).audioClips.size(); ++i) {
 		// Note that as of 3.5.0 data format the clip IDs are still restricted
 		// to actual item index in array, so we don't make any difference
 		// between game versions, for now.
-		game.audioClips[i].id = i;
-		ccRegisterManagedObject(&game.audioClips[i], &ccDynamicAudioClip);
-		ccAddExternalDynamicObject(game.audioClips[i].scriptName, &game.audioClips[i], &ccDynamicAudioClip);
+		_GP(game).audioClips[i].id = i;
+		ccRegisterManagedObject(&_GP(game).audioClips[i], &ccDynamicAudioClip);
+		ccAddExternalDynamicObject(_GP(game).audioClips[i].scriptName, &_GP(game).audioClips[i], &ccDynamicAudioClip);
 	}
 }
 
 // Initializes characters and registers them in the script system
 void InitAndRegisterCharacters() {
-	characterScriptObjNames.resize(game.numcharacters);
-	for (int i = 0; i < game.numcharacters; ++i) {
-		game.chars[i].walking = 0;
-		game.chars[i].animating = 0;
-		game.chars[i].pic_xoffs = 0;
-		game.chars[i].pic_yoffs = 0;
-		game.chars[i].blinkinterval = 140;
-		game.chars[i].blinktimer = game.chars[i].blinkinterval;
-		game.chars[i].index_id = i;
-		game.chars[i].blocking_width = 0;
-		game.chars[i].blocking_height = 0;
-		game.chars[i].prevroom = -1;
-		game.chars[i].loop = 0;
-		game.chars[i].frame = 0;
-		game.chars[i].walkwait = -1;
-		ccRegisterManagedObject(&game.chars[i], &ccDynamicCharacter);
+	characterScriptObjNames.resize(_GP(game).numcharacters);
+	for (int i = 0; i < _GP(game).numcharacters; ++i) {
+		_GP(game).chars[i].walking = 0;
+		_GP(game).chars[i].animating = 0;
+		_GP(game).chars[i].pic_xoffs = 0;
+		_GP(game).chars[i].pic_yoffs = 0;
+		_GP(game).chars[i].blinkinterval = 140;
+		_GP(game).chars[i].blinktimer = _GP(game).chars[i].blinkinterval;
+		_GP(game).chars[i].index_id = i;
+		_GP(game).chars[i].blocking_width = 0;
+		_GP(game).chars[i].blocking_height = 0;
+		_GP(game).chars[i].prevroom = -1;
+		_GP(game).chars[i].loop = 0;
+		_GP(game).chars[i].frame = 0;
+		_GP(game).chars[i].walkwait = -1;
+		ccRegisterManagedObject(&_GP(game).chars[i], &ccDynamicCharacter);
 
 		// export the character's script object
-		characterScriptObjNames[i] = game.chars[i].scrname;
-		ccAddExternalDynamicObject(characterScriptObjNames[i], &game.chars[i], &ccDynamicCharacter);
+		characterScriptObjNames[i] = _GP(game).chars[i].scrname;
+		ccAddExternalDynamicObject(characterScriptObjNames[i], &_GP(game).chars[i], &ccDynamicCharacter);
 	}
 }
 
 // Initializes dialog and registers them in the script system
 void InitAndRegisterDialogs() {
-	scrDialog = new ScriptDialog[game.numdialog];
-	for (int i = 0; i < game.numdialog; ++i) {
+	scrDialog = new ScriptDialog[_GP(game).numdialog];
+	for (int i = 0; i < _GP(game).numdialog; ++i) {
 		scrDialog[i].id = i;
 		scrDialog[i].reserved = 0;
 		ccRegisterManagedObject(&scrDialog[i], &ccDynamicDialog);
 
-		if (!game.dialogScriptNames[i].IsEmpty())
-			ccAddExternalDynamicObject(game.dialogScriptNames[i], &scrDialog[i], &ccDynamicDialog);
+		if (!_GP(game).dialogScriptNames[i].IsEmpty())
+			ccAddExternalDynamicObject(_GP(game).dialogScriptNames[i], &scrDialog[i], &ccDynamicDialog);
 	}
 }
 
@@ -203,13 +204,13 @@ void InitAndRegisterDialogOptions() {
 
 // Initializes gui and registers them in the script system
 HError InitAndRegisterGUI() {
-	scrGui = (ScriptGUI *)malloc(sizeof(ScriptGUI) * game.numgui);
-	for (int i = 0; i < game.numgui; ++i) {
+	scrGui = (ScriptGUI *)malloc(sizeof(ScriptGUI) * _GP(game).numgui);
+	for (int i = 0; i < _GP(game).numgui; ++i) {
 		scrGui[i].id = -1;
 	}
 
-	guiScriptObjNames.resize(game.numgui);
-	for (int i = 0; i < game.numgui; ++i) {
+	guiScriptObjNames.resize(_GP(game).numgui);
+	for (int i = 0; i < _GP(game).numgui; ++i) {
 		// link controls to their parent guis
 		HError err = guis[i].RebuildArray();
 		if (!err)
@@ -233,8 +234,8 @@ void InitAndRegisterInvItems() {
 		scrInv[i].reserved = 0;
 		ccRegisterManagedObject(&scrInv[i], &ccDynamicInv);
 
-		if (!game.invScriptNames[i].IsEmpty())
-			ccAddExternalDynamicObject(game.invScriptNames[i], &scrInv[i], &ccDynamicInv);
+		if (!_GP(game).invScriptNames[i].IsEmpty())
+			ccAddExternalDynamicObject(_GP(game).invScriptNames[i], &scrInv[i], &ccDynamicInv);
 	}
 }
 
@@ -273,7 +274,7 @@ void RegisterStaticArrays() {
 	StaticInventoryArray.Create(&ccDynamicInv, sizeof(ScriptInvItem), sizeof(ScriptInvItem));
 	StaticDialogArray.Create(&ccDynamicDialog, sizeof(ScriptDialog), sizeof(ScriptDialog));
 
-	ccAddExternalStaticArray("character", &game.chars[0], &StaticCharacterArray);
+	ccAddExternalStaticArray("character", &_GP(game).chars[0], &StaticCharacterArray);
 	ccAddExternalStaticArray("object", &scrObj[0], &StaticObjectArray);
 	ccAddExternalStaticArray("gui", &scrGui[0], &StaticGUIArray);
 	ccAddExternalStaticArray("hotspot", &scrHotspot[0], &StaticHotspotArray);
@@ -300,15 +301,15 @@ HError InitAndRegisterGameEntities() {
 
 	RegisterStaticArrays();
 
-	setup_player_character(game.playercharacter);
+	setup_player_character(_GP(game).playercharacter);
 	if (loaded_game_file_version >= kGameVersion_270)
 		ccAddExternalStaticObject("player", &_sc_PlayerCharPtr, &GlobalStaticManager);
 	return HError::None();
 }
 
 void LoadFonts(GameDataVersion data_ver) {
-	for (int i = 0; i < game.numfonts; ++i) {
-		if (!wloadfont_size(i, game.fonts[i]))
+	for (int i = 0; i < _GP(game).numfonts; ++i) {
+		if (!wloadfont_size(i, _GP(game).fonts[i]))
 			quitprintf("Unable to load font %d, no renderer could load a matching file", i);
 	}
 }
@@ -331,8 +332,8 @@ void AllocScriptModules() {
 }
 
 HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion data_ver) {
-	const ScriptAPIVersion base_api = (ScriptAPIVersion)game.options[OPT_BASESCRIPTAPI];
-	const ScriptAPIVersion compat_api = (ScriptAPIVersion)game.options[OPT_SCRIPTCOMPATLEV];
+	const ScriptAPIVersion base_api = (ScriptAPIVersion)_GP(game).options[OPT_BASESCRIPTAPI];
+	const ScriptAPIVersion compat_api = (ScriptAPIVersion)_GP(game).options[OPT_SCRIPTCOMPATLEV];
 	if (data_ver >= kGameVersion_341) {
 		// TODO: find a way to either automate this list of strings or make it more visible (shared & easier to find in engine code)
 		// TODO: stack-allocated strings, here and in other similar places
@@ -343,17 +344,17 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
 	}
 	// If the game was compiled using unsupported version of the script API,
 	// we warn about potential incompatibilities but proceed further.
-	if (game.options[OPT_BASESCRIPTAPI] > kScriptAPI_Current)
+	if (_GP(game).options[OPT_BASESCRIPTAPI] > kScriptAPI_Current)
 		platform->DisplayAlert("Warning: this game requests a higher version of AGS script API, it may not run correctly or run at all.");
 
 	//
 	// 1. Check that the loaded data is valid and compatible with the current
 	// engine capabilities.
 	//
-	if (game.numfonts == 0)
+	if (_GP(game).numfonts == 0)
 		return new GameInitError(kGameInitErr_NoFonts);
-	if (game.audioClipTypes.size() > MAX_AUDIO_TYPES)
-		return new GameInitError(kGameInitErr_TooManyAudioTypes, String::FromFormat("Required: %u, max: %d", game.audioClipTypes.size(), MAX_AUDIO_TYPES));
+	if (_GP(game).audioClipTypes.size() > MAX_AUDIO_TYPES)
+		return new GameInitError(kGameInitErr_TooManyAudioTypes, String::FromFormat("Required: %u, max: %d", _GP(game).audioClipTypes.size(), MAX_AUDIO_TYPES));
 
 	//
 	// 2. Apply overriding config settings
@@ -368,25 +369,25 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
 	// This overriding option re-enables "upscaling". It works ONLY for low-res
 	// resolutions, such as 320x200 and 320x240.
 	if (usetup.override_upscale) {
-		if (game.GetResolutionType() == kGameResolution_320x200)
-			game.SetGameResolution(kGameResolution_640x400);
-		else if (game.GetResolutionType() == kGameResolution_320x240)
-			game.SetGameResolution(kGameResolution_640x480);
+		if (_GP(game).GetResolutionType() == kGameResolution_320x200)
+			_GP(game).SetGameResolution(kGameResolution_640x400);
+		else if (_GP(game).GetResolutionType() == kGameResolution_320x240)
+			_GP(game).SetGameResolution(kGameResolution_640x480);
 	}
 
 	//
 	// 3. Allocate and init game objects
 	//
-	charextra = (CharacterExtras *)calloc(game.numcharacters, sizeof(CharacterExtras));
-	charcache = (CharacterCache *)calloc(1, sizeof(CharacterCache) * game.numcharacters + 5);
-	mls = (MoveList *)calloc(game.numcharacters + MAX_ROOM_OBJECTS + 1, sizeof(MoveList));
-	actSpsCount = game.numcharacters + MAX_ROOM_OBJECTS + 2;
+	charextra = (CharacterExtras *)calloc(_GP(game).numcharacters, sizeof(CharacterExtras));
+	charcache = (CharacterCache *)calloc(1, sizeof(CharacterCache) * _GP(game).numcharacters + 5);
+	mls = (MoveList *)calloc(_GP(game).numcharacters + MAX_ROOM_OBJECTS + 1, sizeof(MoveList));
+	actSpsCount = _GP(game).numcharacters + MAX_ROOM_OBJECTS + 2;
 	actsps = (Bitmap **)calloc(actSpsCount, sizeof(Bitmap *));
 	actspsbmp = (IDriverDependantBitmap **)calloc(actSpsCount, sizeof(IDriverDependantBitmap *));
 	actspswb = (Bitmap **)calloc(actSpsCount, sizeof(Bitmap *));
 	actspswbbmp = (IDriverDependantBitmap **)calloc(actSpsCount, sizeof(IDriverDependantBitmap *));
 	actspswbcache = (CachedActSpsData *)calloc(actSpsCount, sizeof(CachedActSpsData));
-	play.charProps.resize(game.numcharacters);
+	play.charProps.resize(_GP(game).numcharacters);
 	old_dialog_scripts = ents.OldDialogScripts;
 	old_speech_lines = ents.OldSpeechLines;
 	HError err = InitAndRegisterGameEntities();
@@ -401,12 +402,12 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
 	ifacepopped = -1;
 
 	String svg_suffix;
-	if (game.saveGameFileExtension[0] != 0)
-		svg_suffix.Format(".%s", game.saveGameFileExtension);
+	if (_GP(game).saveGameFileExtension[0] != 0)
+		svg_suffix.Format(".%s", _GP(game).saveGameFileExtension);
 	set_save_game_suffix(svg_suffix);
 
-	play.score_sound = game.scoreClipID;
-	play.fade_effect = game.options[OPT_FADETYPE];
+	play.score_sound = _GP(game).scoreClipID;
+	play.fade_effect = _GP(game).options[OPT_FADETYPE];
 
 	//
 	// 5. Initialize runtime state of certain game objects
@@ -415,7 +416,7 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
 		// labels are not clickable by default
 		guilabels[i].SetClickable(false);
 	}
-	play.gui_draw_order = (int32_t *)calloc(game.numgui * sizeof(int32_t), 1);
+	play.gui_draw_order = (int32_t *)calloc(_GP(game).numgui * sizeof(int32_t), 1);
 	update_gui_zorder();
 	calculate_reserved_channel_count();
 
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 085fbe669d..c5691798a2 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -61,7 +61,7 @@
 #include "ags/shared/util/stream.h"
 #include "ags/shared/util/string_utils.h"
 #include "ags/engine/media/audio/audio_system.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -69,10 +69,10 @@ namespace AGS3 {
 using namespace Shared;
 using namespace Engine;
 
-// function is currently implemented in game.cpp
+// function is currently implemented in _GP(game).cpp
 HSaveError restore_game_data(Stream *in, SavegameVersion svg_version, const PreservedParams &pp, RestoredData &r_data);
 
-extern GameSetupStruct game;
+
 extern Bitmap **guibg;
 extern AGS::Engine::IDriverDependantBitmap **guibgbmp;
 extern AGS::Engine::IGraphicsDriver *gfxDriver;
@@ -132,7 +132,7 @@ String GetSavegameErrorText(SavegameErrorType err) {
 	case kSvgErr_IncompatibleEngine:
 		return "Save was written by incompatible engine, or file is corrupted.";
 	case kSvgErr_GameGuidMismatch:
-		return "Game GUID does not match, saved by a different game.";
+		return "Game GUID does not match, saved by a different _GP(game).";
 	case kSvgErr_ComponentListOpeningTagFormat:
 		return "Failed to parse opening tag of the components list.";
 	case kSvgErr_ComponentListClosingTagMissing:
@@ -154,7 +154,7 @@ String GetSavegameErrorText(SavegameErrorType err) {
 	case kSvgErr_UnsupportedComponentVersion:
 		return "Component data version not supported.";
 	case kSvgErr_GameContentAssertion:
-		return "Saved content does not match current game.";
+		return "Saved content does not match current _GP(game).";
 	case kSvgErr_InconsistentData:
 		return "Inconsistent save data, or file is corrupted.";
 	case kSvgErr_InconsistentPlugin:
@@ -337,8 +337,8 @@ void DoBeforeRestore(PreservedParams &pp) {
 
 	// cleanup dynamic sprites
 	// NOTE: sprite 0 is a special constant sprite that cannot be dynamic
-	for (int i = 1; i < spriteset.GetSpriteSlotCount(); ++i) {
-		if (game.SpriteInfos[i].Flags & SPF_DYNAMICALLOC) {
+	for (int i = 1; i < _GP(spriteset).GetSpriteSlotCount(); ++i) {
+		if (_GP(game).SpriteInfos[i].Flags & SPF_DYNAMICALLOC) {
 			// do this early, so that it changing guibuts doesn't
 			// affect the restored data
 			free_dynamic_sprite(i);
@@ -346,7 +346,7 @@ void DoBeforeRestore(PreservedParams &pp) {
 	}
 
 	// cleanup GUI backgrounds
-	for (int i = 0; i < game.numgui; ++i) {
+	for (int i = 0; i < _GP(game).numgui; ++i) {
 		delete guibg[i];
 		guibg[i] = nullptr;
 
@@ -387,7 +387,7 @@ void DoBeforeRestore(PreservedParams &pp) {
 
 	// unregister gui controls from API exports
 	// TODO: find out why are we doing this here? is this really necessary?
-	for (int i = 0; i < game.numgui; ++i) {
+	for (int i = 0; i < _GP(game).numgui; ++i) {
 		unexport_gui_controls(i);
 	}
 	// Clear the managed object pool
@@ -457,7 +457,7 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 		dynamicallyCreatedSurfaces[i] = r_data.DynamicSurfaces[i];
 	}
 
-	for (int i = 0; i < game.numgui; ++i)
+	for (int i = 0; i < _GP(game).numgui; ++i)
 		export_gui_controls(i);
 	update_gui_zorder();
 
@@ -478,7 +478,7 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 				Math::Min((size_t)moduleInst[i]->globaldatasize, r_data.ScriptModules[i].Len));
 	}
 
-	setup_player_character(game.playercharacter);
+	setup_player_character(_GP(game).playercharacter);
 
 	// Save some parameters to restore them after room load
 	int gstimer = play.gscript_timer;
@@ -509,7 +509,7 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 	if (r_data.CursorMode == MODE_USE)
 		SetActiveInventory(playerchar->activeinv);
 	// ensure that the current cursor is locked
-	spriteset.Precache(game.mcurs[r_data.CursorID].pic);
+	_GP(spriteset).Precache(_GP(game).mcurs[r_data.CursorID].pic);
 
 	::AGS::g_vm->set_window_title(play.game_name);
 
@@ -538,7 +538,7 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 		on_background_frame_change();
 	}
 
-	gui_disabled_style = convert_gui_disabled_style(game.options[OPT_DISABLEOFF]);
+	gui_disabled_style = convert_gui_disabled_style(_GP(game).options[OPT_DISABLEOFF]);
 
 	// restore the queue now that the music is playing
 	play.music_queue_size = queuedMusicSize;
@@ -560,11 +560,11 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 			const RestoredData::ChannelInfo &chan_info = r_data.AudioChans[i];
 			if (chan_info.ClipID < 0)
 				continue;
-			if ((size_t)chan_info.ClipID >= game.audioClips.size()) {
+			if ((size_t)chan_info.ClipID >= _GP(game).audioClips.size()) {
 				return new SavegameError(kSvgErr_GameObjectInitFailed,
-					String::FromFormat("Invalid audio clip index: %d (clip count: %u).", chan_info.ClipID, game.audioClips.size()));
+					String::FromFormat("Invalid audio clip index: %d (clip count: %u).", chan_info.ClipID, _GP(game).audioClips.size()));
 			}
-			play_audio_clip_on_channel(i, &game.audioClips[chan_info.ClipID],
+			play_audio_clip_on_channel(i, &_GP(game).audioClips[chan_info.ClipID],
 				chan_info.Priority, chan_info.Repeat, chan_info.Pos);
 
 			auto *ch = lock.GetChannel(i);
@@ -602,8 +602,8 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 	}
 	update_directional_sound_vol();
 
-	for (int i = 0; i < game.numgui; ++i) {
-		guibg[i] = BitmapHelper::CreateBitmap(guis[i].Width, guis[i].Height, game.GetColorDepth());
+	for (int i = 0; i < _GP(game).numgui; ++i) {
+		guibg[i] = BitmapHelper::CreateBitmap(guis[i].Width, guis[i].Height, _GP(game).GetColorDepth());
 		guibg[i] = ReplaceBitmapWithSupportedFormat(guibg[i]);
 	}
 
@@ -674,11 +674,11 @@ void WriteDescription(Stream *out, const String &user_text, const Bitmap *user_i
 	// Enviroment information
 	StrUtil::WriteString("Adventure Game Studio run-time engine", out);
 	StrUtil::WriteString(_G(EngineVersion).LongString, out);
-	StrUtil::WriteString(game.guid, out);
-	StrUtil::WriteString(game.gamename, out);
+	StrUtil::WriteString(_GP(game).guid, out);
+	StrUtil::WriteString(_GP(game).gamename, out);
 	StrUtil::WriteString(ResPaths.GamePak.Name, out);
 	out->WriteInt32(loaded_game_file_version);
-	out->WriteInt32(game.GetColorDepth());
+	out->WriteInt32(_GP(game).GetColorDepth());
 	// User description
 	StrUtil::WriteString(user_text, out);
 	WriteSaveImage(out, user_image);
@@ -698,12 +698,12 @@ PStream StartSavegame(const String &filename, const String &user_text, const Bit
 	vistaHeader.dwThumbnailOffsetHigherDword = 0;
 	vistaHeader.dwThumbnailOffsetLowerDword = 0;
 	vistaHeader.dwThumbnailSize = 0;
-	convert_guid_from_text_to_binary(game.guid, &vistaHeader.guidGameId[0]);
+	convert_guid_from_text_to_binary(_GP(game).guid, &vistaHeader.guidGameId[0]);
 
 #if 1
 	vistaHeader.setSaveName(user_text);
 #else
-	uconvert(game.gamename, U_ASCII, (char *)&vistaHeader.szGameName[0], U_UNICODE, RM_MAXLENGTH);
+	uconvert(_GP(game).gamename, U_ASCII, (char *)&vistaHeader.szGameName[0], U_UNICODE, RM_MAXLENGTH);
 	uconvert(user_text, U_ASCII, (char *)&vistaHeader.szSaveName[0], U_UNICODE, RM_MAXLENGTH);
 #endif
 
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 6aa01c7457..1e7c40fdef 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-//include <map>
-
 #include "ags/shared/ac/audiocliptype.h"
 #include "ags/engine/ac/character.h"
 #include "ags/shared/ac/common.h"
@@ -59,12 +57,13 @@
 #include "ags/engine/script/script.h"
 #include "ags/shared/util/filestream.h" // TODO: needed only because plugins expect file handle
 #include "ags/engine/media/audio/audio_system.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace Shared;
 
-extern GameSetupStruct game;
+
 extern color palette[256];
 extern DialogTopic *dialog;
 extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
@@ -205,7 +204,7 @@ void WriteViewportState(const Viewport &view, Stream *out) {
 
 HSaveError WriteGameState(PStream out) {
 	// Game base
-	game.WriteForSavegame(out);
+	_GP(game).WriteForSavegame(out);
 	// Game palette
 	out->SafeWriteArray(palette, PALETTE_COUNT);
 
@@ -294,7 +293,7 @@ HSaveError ReadGameState(PStream in, int32_t cmp_ver, const PreservedParams &pp,
 	HSaveError err;
 	GameStateSvgVersion svg_ver = (GameStateSvgVersion)cmp_ver;
 	// Game base
-	game.ReadFromSavegame(in);
+	_GP(game).ReadFromSavegame(in);
 	// Game palette
 	in->SafeReadArray(palette, PALETTE_COUNT);
 
@@ -349,12 +348,12 @@ HSaveError WriteAudio(PStream out) {
 	AudioChannelsLock lock;
 
 	// Game content assertion
-	out->WriteInt32(game.audioClipTypes.size());
-	out->WriteInt32(game.audioClips.size()); // [ivan-mogilko] not necessary, kept only to avoid changing save format
+	out->WriteInt32(_GP(game).audioClipTypes.size());
+	out->WriteInt32(_GP(game).audioClips.size()); // [ivan-mogilko] not necessary, kept only to avoid changing save format
 
 	// Audio types
-	for (size_t i = 0; i < game.audioClipTypes.size(); ++i) {
-		game.audioClipTypes[i].WriteToSavegame(out.get());
+	for (size_t i = 0; i < _GP(game).audioClipTypes.size(); ++i) {
+		_GP(game).audioClipTypes[i].WriteToSavegame(out.get());
 		out->WriteInt32(play.default_audio_type_volumes[i]);
 	}
 
@@ -398,13 +397,13 @@ HSaveError ReadAudio(PStream in, int32_t cmp_ver, const PreservedParams &pp, Res
 	HSaveError err;
 
 	// Game content assertion
-	if (!AssertGameContent(err, in->ReadInt32(), game.audioClipTypes.size(), "Audio Clip Types"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).audioClipTypes.size(), "Audio Clip Types"))
 		return err;
 	in->ReadInt32(); // audio clip count
 
 	// Audio types
-	for (size_t i = 0; i < game.audioClipTypes.size(); ++i) {
-		game.audioClipTypes[i].ReadFromSavegame(in.get());
+	for (size_t i = 0; i < _GP(game).audioClipTypes.size(); ++i) {
+		_GP(game).audioClipTypes[i].ReadFromSavegame(in.get());
 		play.default_audio_type_volumes[i] = in->ReadInt32();
 	}
 
@@ -486,13 +485,13 @@ HSaveError ReadInteraction272(Interaction &intr, Stream *in) {
 }
 
 HSaveError WriteCharacters(PStream out) {
-	out->WriteInt32(game.numcharacters);
-	for (int i = 0; i < game.numcharacters; ++i) {
-		game.chars[i].WriteToFile(out.get());
+	out->WriteInt32(_GP(game).numcharacters);
+	for (int i = 0; i < _GP(game).numcharacters; ++i) {
+		_GP(game).chars[i].WriteToFile(out.get());
 		charextra[i].WriteToFile(out.get());
 		Properties::WriteValues(play.charProps[i], out.get());
 		if (loaded_game_file_version <= kGameVersion_272)
-			WriteTimesRun272(*game.intrChar[i], out.get());
+			WriteTimesRun272(*_GP(game).intrChar[i], out.get());
 		// character movement path cache
 		mls[CHMLSOFFS + i].WriteToFile(out.get());
 	}
@@ -501,14 +500,14 @@ HSaveError WriteCharacters(PStream out) {
 
 HSaveError ReadCharacters(PStream in, int32_t cmp_ver, const PreservedParams &pp, RestoredData &r_data) {
 	HSaveError err;
-	if (!AssertGameContent(err, in->ReadInt32(), game.numcharacters, "Characters"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numcharacters, "Characters"))
 		return err;
-	for (int i = 0; i < game.numcharacters; ++i) {
-		game.chars[i].ReadFromFile(in.get());
+	for (int i = 0; i < _GP(game).numcharacters; ++i) {
+		_GP(game).chars[i].ReadFromFile(in.get());
 		charextra[i].ReadFromFile(in.get());
 		Properties::ReadValues(play.charProps[i], in.get());
 		if (loaded_game_file_version <= kGameVersion_272)
-			ReadTimesRun272(*game.intrChar[i], in.get());
+			ReadTimesRun272(*_GP(game).intrChar[i], in.get());
 		// character movement path cache
 		err = mls[CHMLSOFFS + i].ReadFromFile(in.get(), cmp_ver > 0 ? 1 : 0);
 		if (!err)
@@ -518,8 +517,8 @@ HSaveError ReadCharacters(PStream in, int32_t cmp_ver, const PreservedParams &pp
 }
 
 HSaveError WriteDialogs(PStream out) {
-	out->WriteInt32(game.numdialog);
-	for (int i = 0; i < game.numdialog; ++i) {
+	out->WriteInt32(_GP(game).numdialog);
+	for (int i = 0; i < _GP(game).numdialog; ++i) {
 		dialog[i].WriteToSavegame(out.get());
 	}
 	return HSaveError::None();
@@ -527,9 +526,9 @@ HSaveError WriteDialogs(PStream out) {
 
 HSaveError ReadDialogs(PStream in, int32_t cmp_ver, const PreservedParams &pp, RestoredData &r_data) {
 	HSaveError err;
-	if (!AssertGameContent(err, in->ReadInt32(), game.numdialog, "Dialogs"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numdialog, "Dialogs"))
 		return err;
-	for (int i = 0; i < game.numdialog; ++i) {
+	for (int i = 0; i < _GP(game).numdialog; ++i) {
 		dialog[i].ReadFromSavegame(in.get());
 	}
 	return err;
@@ -538,8 +537,8 @@ HSaveError ReadDialogs(PStream in, int32_t cmp_ver, const PreservedParams &pp, R
 HSaveError WriteGUI(PStream out) {
 	// GUI state
 	WriteFormatTag(out, "GUIs");
-	out->WriteInt32(game.numgui);
-	for (int i = 0; i < game.numgui; ++i)
+	out->WriteInt32(_GP(game).numgui);
+	for (int i = 0; i < _GP(game).numgui; ++i)
 		guis[i].WriteToSavegame(out.get());
 
 	WriteFormatTag(out, "GUIButtons");
@@ -586,9 +585,9 @@ HSaveError ReadGUI(PStream in, int32_t cmp_ver, const PreservedParams &pp, Resto
 	// GUI state
 	if (!AssertFormatTagStrict(err, in, "GUIs"))
 		return err;
-	if (!AssertGameContent(err, in->ReadInt32(), game.numgui, "GUIs"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numgui, "GUIs"))
 		return err;
-	for (int i = 0; i < game.numgui; ++i)
+	for (int i = 0; i < _GP(game).numgui; ++i)
 		guis[i].ReadFromSavegame(in.get(), svg_ver);
 
 	if (!AssertFormatTagStrict(err, in, "GUIButtons"))
@@ -646,50 +645,50 @@ HSaveError ReadGUI(PStream in, int32_t cmp_ver, const PreservedParams &pp, Resto
 }
 
 HSaveError WriteInventory(PStream out) {
-	out->WriteInt32(game.numinvitems);
-	for (int i = 0; i < game.numinvitems; ++i) {
-		game.invinfo[i].WriteToSavegame(out.get());
+	out->WriteInt32(_GP(game).numinvitems);
+	for (int i = 0; i < _GP(game).numinvitems; ++i) {
+		_GP(game).invinfo[i].WriteToSavegame(out.get());
 		Properties::WriteValues(play.invProps[i], out.get());
 		if (loaded_game_file_version <= kGameVersion_272)
-			WriteTimesRun272(*game.intrInv[i], out.get());
+			WriteTimesRun272(*_GP(game).intrInv[i], out.get());
 	}
 	return HSaveError::None();
 }
 
 HSaveError ReadInventory(PStream in, int32_t cmp_ver, const PreservedParams &pp, RestoredData &r_data) {
 	HSaveError err;
-	if (!AssertGameContent(err, in->ReadInt32(), game.numinvitems, "Inventory Items"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numinvitems, "Inventory Items"))
 		return err;
-	for (int i = 0; i < game.numinvitems; ++i) {
-		game.invinfo[i].ReadFromSavegame(in.get());
+	for (int i = 0; i < _GP(game).numinvitems; ++i) {
+		_GP(game).invinfo[i].ReadFromSavegame(in.get());
 		Properties::ReadValues(play.invProps[i], in.get());
 		if (loaded_game_file_version <= kGameVersion_272)
-			ReadTimesRun272(*game.intrInv[i], in.get());
+			ReadTimesRun272(*_GP(game).intrInv[i], in.get());
 	}
 	return err;
 }
 
 HSaveError WriteMouseCursors(PStream out) {
-	out->WriteInt32(game.numcursors);
-	for (int i = 0; i < game.numcursors; ++i) {
-		game.mcurs[i].WriteToSavegame(out.get());
+	out->WriteInt32(_GP(game).numcursors);
+	for (int i = 0; i < _GP(game).numcursors; ++i) {
+		_GP(game).mcurs[i].WriteToSavegame(out.get());
 	}
 	return HSaveError::None();
 }
 
 HSaveError ReadMouseCursors(PStream in, int32_t cmp_ver, const PreservedParams &pp, RestoredData &r_data) {
 	HSaveError err;
-	if (!AssertGameContent(err, in->ReadInt32(), game.numcursors, "Mouse Cursors"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numcursors, "Mouse Cursors"))
 		return err;
-	for (int i = 0; i < game.numcursors; ++i) {
-		game.mcurs[i].ReadFromSavegame(in.get());
+	for (int i = 0; i < _GP(game).numcursors; ++i) {
+		_GP(game).mcurs[i].ReadFromSavegame(in.get());
 	}
 	return err;
 }
 
 HSaveError WriteViews(PStream out) {
-	out->WriteInt32(game.numviews);
-	for (int view = 0; view < game.numviews; ++view) {
+	out->WriteInt32(_GP(game).numviews);
+	for (int view = 0; view < _GP(game).numviews; ++view) {
 		out->WriteInt32(views[view].numLoops);
 		for (int loop = 0; loop < views[view].numLoops; ++loop) {
 			out->WriteInt32(views[view].loops[loop].numFrames);
@@ -704,9 +703,9 @@ HSaveError WriteViews(PStream out) {
 
 HSaveError ReadViews(PStream in, int32_t cmp_ver, const PreservedParams &pp, RestoredData &r_data) {
 	HSaveError err;
-	if (!AssertGameContent(err, in->ReadInt32(), game.numviews, "Views"))
+	if (!AssertGameContent(err, in->ReadInt32(), _GP(game).numviews, "Views"))
 		return err;
-	for (int view = 0; view < game.numviews; ++view) {
+	for (int view = 0; view < _GP(game).numviews; ++view) {
 		if (!AssertGameObjectContent(err, in->ReadInt32(), views[view].numLoops,
 		                             "Loops", "View", view))
 			return err;
@@ -729,13 +728,13 @@ HSaveError WriteDynamicSprites(PStream out) {
 	out->WriteInt32(0); // top index
 	int count = 0;
 	int top_index = 1;
-	for (int i = 1; i < spriteset.GetSpriteSlotCount(); ++i) {
-		if (game.SpriteInfos[i].Flags & SPF_DYNAMICALLOC) {
+	for (int i = 1; i < _GP(spriteset).GetSpriteSlotCount(); ++i) {
+		if (_GP(game).SpriteInfos[i].Flags & SPF_DYNAMICALLOC) {
 			count++;
 			top_index = i;
 			out->WriteInt32(i);
-			out->WriteInt32(game.SpriteInfos[i].Flags);
-			serialize_bitmap(spriteset[i], out.get());
+			out->WriteInt32(_GP(game).SpriteInfos[i].Flags);
+			serialize_bitmap(_GP(spriteset)[i], out.get());
 		}
 	}
 	const soff_t end_pos = out->GetPosition();
@@ -752,12 +751,12 @@ HSaveError ReadDynamicSprites(PStream in, int32_t cmp_ver, const PreservedParams
 	// ensure the sprite set is at least large enough
 	// to accomodate top dynamic sprite index
 	const int top_index = in->ReadInt32();
-	spriteset.EnlargeTo(top_index);
+	_GP(spriteset).EnlargeTo(top_index);
 	for (int i = 0; i < spr_count; ++i) {
 		int id = in->ReadInt32();
 		int flags = in->ReadInt32();
 		add_dynamic_sprite(id, read_serialized_bitmap(in.get()));
-		game.SpriteInfos[id].Flags = flags;
+		_GP(game).SpriteInfos[id].Flags = flags;
 	}
 	return err;
 }
diff --git a/engines/ags/engine/gfx/graphicsdriver.h b/engines/ags/engine/gfx/graphicsdriver.h
index 1c7a9da216..0c0c36ad79 100644
--- a/engines/ags/engine/gfx/graphicsdriver.h
+++ b/engines/ags/engine/gfx/graphicsdriver.h
@@ -158,7 +158,7 @@ public:
 	// the final resolution, as opposed to drawing to native-resolution buffer
 	// and scaling to final frame. The effect may be that sprites that are
 	// drawn with additional fractional scaling will appear more detailed than
-	// the rest of the game. The effect is stronger for the low-res games being
+	// the rest of the _GP(game). The effect is stronger for the low-res games being
 	// rendered in the high-res mode.
 	virtual void RenderSpritesAtScreenResolution(bool enabled, int supersampling = 1) = 0;
 	// TODO: move fade-in/out/boxout functions out of the graphics driver!! make everything render through
diff --git a/engines/ags/engine/gui/cscidialog.cpp b/engines/ags/engine/gui/cscidialog.cpp
index 48da261d1f..fc60eeb32b 100644
--- a/engines/ags/engine/gui/cscidialog.cpp
+++ b/engines/ags/engine/gui/cscidialog.cpp
@@ -42,7 +42,7 @@
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
 #include "ags/engine/ac/timer.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/gui/gui_engine.cpp b/engines/ags/engine/gui/gui_engine.cpp
index b248e3327a..be92431187 100644
--- a/engines/ags/engine/gui/gui_engine.cpp
+++ b/engines/ags/engine/gui/gui_engine.cpp
@@ -26,8 +26,6 @@
 //
 //=============================================================================
 
-// Headers, as they are in acgui.cpp
-//pragma unmanaged
 #include "ags/shared/ac/game_version.h"
 #include "ags/engine/ac/system.h"
 #include "ags/shared/font/fonts.h"
@@ -36,13 +34,13 @@
 #include "ags/shared/gui/guilabel.h"
 #include "ags/shared/gui/guilistbox.h"
 #include "ags/shared/gui/guitextbox.h"
-//include <ctype.h>
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/ac/global_translation.h"
 #include "ags/engine/ac/string.h"
 #include "ags/shared/ac/spritecache.h"
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/gfx/blender.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -56,8 +54,8 @@ extern void replace_macro_tokens(const char *, String &);
 extern void ensure_text_valid_for_font(char *, int);
 //
 
-extern SpriteCache spriteset; // in ac_runningame
-extern GameSetupStruct game;
+ // in ac_runningame
+
 
 bool GUIMain::HasAlphaChannel() const {
 	if (this->BgImage > 0) {
@@ -69,11 +67,11 @@ bool GUIMain::HasAlphaChannel() const {
 		return false;
 	}
 	// transparent background, enable alpha blending
-	return game.GetColorDepth() >= 24 &&
+	return _GP(game).GetColorDepth() >= 24 &&
 		// transparent background have alpha channel only since 3.2.0;
 		// "classic" gui rendering mode historically had non-alpha transparent backgrounds
 		// (3.2.0 broke the compatibility, now we restore it)
-		loaded_game_file_version >= kGameVersion_320 && game.options[OPT_NEWGUIALPHA] != kGuiAlphaRender_Legacy;
+		loaded_game_file_version >= kGameVersion_320 && _GP(game).options[OPT_NEWGUIALPHA] != kGuiAlphaRender_Legacy;
 }
 
 //=============================================================================
@@ -89,15 +87,15 @@ void check_font(int32_t *fontnum) {
 //=============================================================================
 
 int get_adjusted_spritewidth(int spr) {
-	return spriteset[spr]->GetWidth();
+	return _GP(spriteset)[spr]->GetWidth();
 }
 
 int get_adjusted_spriteheight(int spr) {
-	return spriteset[spr]->GetHeight();
+	return _GP(spriteset)[spr]->GetHeight();
 }
 
 bool is_sprite_alpha(int spr) {
-	return ((game.SpriteInfos[spr].Flags & SPF_ALPHACHANNEL) != 0);
+	return ((_GP(game).SpriteInfos[spr].Flags & SPF_ALPHACHANNEL) != 0);
 }
 
 void set_eip_guiobj(int eip) {
diff --git a/engines/ags/engine/gui/guidialog.cpp b/engines/ags/engine/gui/guidialog.cpp
index d80f2429b3..e2ad58836e 100644
--- a/engines/ags/engine/gui/guidialog.cpp
+++ b/engines/ags/engine/gui/guidialog.cpp
@@ -20,20 +20,18 @@
  *
  */
 
-//include <cstdio>
 #include "ags/engine/gui/guidialog.h"
-
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/draw.h"
 #include "ags/engine/ac/game.h"
 #include "ags/engine/ac/gamesetup.h"
 #include "ags/shared/ac/gamesetupstruct.h"
 #include "ags/engine/gui/cscidialog.h"
-//include <cctype> //isdigit()
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/gfx/graphicsdriver.h"
 #include "ags/engine/debugging/debug_log.h"
 #include "engines/savestate.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -43,7 +41,7 @@ using namespace AGS::Engine;
 
 extern IGraphicsDriver *gfxDriver;
 extern GameSetup usetup;
-extern GameSetupStruct game;
+
 
 namespace {
 
@@ -84,7 +82,7 @@ Bitmap *prepare_gui_screen(int x, int y, int width, int height, bool opaque) {
 	if (windowBuffer) {
 		windowBuffer = recycle_bitmap(windowBuffer, windowBuffer->GetColorDepth(), windowPosWidth, windowPosHeight, !opaque);
 	} else {
-		windowBuffer = BitmapHelper::CreateBitmap(windowPosWidth, windowPosHeight, game.GetColorDepth());
+		windowBuffer = BitmapHelper::CreateBitmap(windowPosWidth, windowPosHeight, _GP(game).GetColorDepth());
 		windowBuffer = ReplaceBitmapWithSupportedFormat(windowBuffer);
 	}
 	dialogDDB = recycle_ddb_bitmap(dialogDDB, windowBuffer, false, opaque);
diff --git a/engines/ags/engine/gui/mylistbox.cpp b/engines/ags/engine/gui/mylistbox.cpp
index 107e82e82f..a4e5d08ec7 100644
--- a/engines/ags/engine/gui/mylistbox.cpp
+++ b/engines/ags/engine/gui/mylistbox.cpp
@@ -29,7 +29,7 @@
 #include "ags/engine/gui/guidialog.h"
 #include "ags/engine/gui/guidialoginternaldefs.h"
 #include "ags/engine/gui/mylistbox.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/gui/mypushbutton.cpp b/engines/ags/engine/gui/mypushbutton.cpp
index 5a618d4bb5..5fca6779a3 100644
--- a/engines/ags/engine/gui/mypushbutton.cpp
+++ b/engines/ags/engine/gui/mypushbutton.cpp
@@ -32,7 +32,7 @@
 #include "ags/shared/gfx/bitmap.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
 #include "ags/engine/ac/timer.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/gui/newcontrol.cpp b/engines/ags/engine/gui/newcontrol.cpp
index 6738c54d57..320479976c 100644
--- a/engines/ags/engine/gui/newcontrol.cpp
+++ b/engines/ags/engine/gui/newcontrol.cpp
@@ -23,7 +23,7 @@
 #include "ags/engine/gui/newcontrol.h"
 #include "ags/engine/gui/guidialog.h"
 #include "ags/engine/gui/guidialoginternaldefs.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/main/config.cpp b/engines/ags/engine/main/config.cpp
index 557ad42e7e..e4fb44663d 100644
--- a/engines/ags/engine/main/config.cpp
+++ b/engines/ags/engine/main/config.cpp
@@ -43,7 +43,7 @@
 #include "ags/shared/util/path.h"
 #include "ags/shared/util/string_utils.h"
 #include "ags/engine/media/audio/audio_system.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "common/config-manager.h"
 
 namespace AGS3 {
@@ -51,9 +51,9 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern GameSetup usetup;
-extern SpriteCache spriteset;
+
 extern GameState play;
 
 // Filename of the default config file, the one found in the game installation
@@ -201,7 +201,7 @@ int convert_fp_to_scaling(uint32_t scaling) {
 void graphics_mode_get_defaults(bool windowed, ScreenSizeSetup &scsz_setup, GameFrameSetup &frame_setup) {
 	scsz_setup.Size = Size();
 	if (windowed) {
-		// For the windowed we define mode by the scaled game.
+		// For the windowed we define mode by the scaled _GP(game).
 		scsz_setup.SizeDef = kScreenDef_ByGameScaling;
 		scsz_setup.MatchDeviceRatio = false;
 		frame_setup = usetup.Screen.WinGameFrame;
@@ -395,7 +395,7 @@ void apply_config(const ConfigTree &cfg) {
 
 		int cache_size_kb = INIreadint(cfg, "misc", "cachemax", DEFAULTCACHESIZE_KB);
 		if (cache_size_kb > 0)
-			spriteset.SetMaxCacheSize((size_t)cache_size_kb * 1024);
+			_GP(spriteset).SetMaxCacheSize((size_t)cache_size_kb * 1024);
 
 		usetup.mouse_auto_lock = INIreadint(cfg, "mouse", "auto_lock") > 0;
 
@@ -490,7 +490,7 @@ void save_config_file() {
 	}
 
 	// Other game options that could be changed at runtime
-	if (game.options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_UserDefined)
+	if (_GP(game).options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_UserDefined)
 		cfg["graphics"]["render_at_screenres"] = String::FromFormat("%d", usetup.RenderAtScreenRes ? 1 : 0);
 	cfg["mouse"]["control_enabled"] = String::FromFormat("%d", usetup.mouse_ctrl_enabled ? 1 : 0);
 	cfg["mouse"]["speed"] = String::FromFormat("%f", Mouse::GetSpeed());
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 9dfc9c9982..5c773ac680 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -25,13 +25,7 @@
 //
 
 #include "ags/shared/core/platform.h"
-#include "ags/engine/globals.h"
-
-//include <errno.h>
-#if AGS_PLATFORM_OS_WINDOWS
-//include <process.h>  // _spawnl
-#endif
-
+#include "ags/globals.h"
 #include "ags/engine/main/mainheader.h"
 #include "ags/engine/ac/asset_helper.h"
 #include "ags/shared/ac/common.h"
@@ -80,6 +74,7 @@
 #include "ags/shared/util/error.h"
 #include "ags/shared/util/misc.h"
 #include "ags/shared/util/path.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 #include "common/fs.h"
 
@@ -91,13 +86,11 @@ using namespace AGS::Engine;
 extern char check_dynamic_sprites_at_exit;
 extern int our_eip;
 extern GameSetup usetup;
-extern GameSetupStruct game;
 extern int proper_exit;
 extern char pexbuf[STD_BUFFER_SIZE];
-extern SpriteCache spriteset;
+
 extern ObjectCache objcache[MAX_ROOM_OBJECTS];
 extern ScriptObject scrObj[MAX_ROOM_OBJECTS];
-extern ViewStruct *views;
 extern int displayed_room;
 extern int eip_guinum;
 extern int eip_guiobj;
@@ -111,7 +104,7 @@ extern CharacterExtras *charextra;
 extern CharacterInfo *playerchar;
 extern Bitmap **guibg;
 extern IDriverDependantBitmap **guibgbmp;
-
+extern ViewStruct *views;
 ResourcePaths ResPaths;
 
 t_engine_pre_init_callback engine_pre_init_callback = nullptr;
@@ -367,7 +360,7 @@ void engine_locate_speech_pak() {
 
 void engine_locate_audio_pak() {
 	play.separate_music_lib = 0;
-	String music_file = game.GetAudioVOXName();
+	String music_file = _GP(game).GetAudioVOXName();
 	String music_filepath = find_assetlib(music_file);
 	if (!music_filepath.IsEmpty()) {
 		if (AssetManager::SetDataFile(music_filepath) == kAssetNoError) {
@@ -490,8 +483,8 @@ int engine_check_register_game() {
 
 void engine_init_title() {
 	our_eip = -91;
-	::AGS::g_vm->set_window_title(game.gamename);
-	Debug::Printf(kDbgMsg_Info, "Game title: '%s'", game.gamename);
+	::AGS::g_vm->set_window_title(_GP(game).gamename);
+	Debug::Printf(kDbgMsg_Info, "Game title: '%s'", _GP(game).gamename);
 }
 
 void engine_init_directories() {
@@ -530,7 +523,7 @@ void engine_init_directories() {
 	// if there is no custom path, or if custom path failed, use default system path
 	if (!res) {
 		char newDirBuffer[MAX_PATH];
-		sprintf(newDirBuffer, "%s/%s", UserSavedgamesRootToken, game.saveGameFolderName);
+		sprintf(newDirBuffer, "%s/%s", UserSavedgamesRootToken, _GP(game).saveGameFolderName);
 		SetSaveGameDirectoryPath(newDirBuffer);
 	}
 }
@@ -595,7 +588,7 @@ int engine_check_disk_space() {
 
 int engine_check_font_was_loaded() {
 	if (!font_first_renderer_loaded()) {
-		platform->DisplayAlert("No game fonts found. At least one font is required to run the game.");
+		platform->DisplayAlert("No game fonts found. At least one font is required to run the _GP(game).");
 		proper_exit = 1;
 		return EXIT_ERROR;
 	}
@@ -615,7 +608,7 @@ void show_preload() {
 			gfxDriver->GetMemoryBackBuffer()->Clear();
 
 		const Rect &view = play.GetMainViewport();
-		Bitmap *tsc = BitmapHelper::CreateBitmapCopy(splashsc, game.GetColorDepth());
+		Bitmap *tsc = BitmapHelper::CreateBitmapCopy(splashsc, _GP(game).GetColorDepth());
 		if (!gfxDriver->HasAcceleratedTransform() && view.GetSize() != tsc->GetSize()) {
 			Bitmap *stretched = new Bitmap(view.GetWidth(), view.GetHeight(), tsc->GetColorDepth());
 			stretched->StretchBlt(tsc, RectWH(0, 0, view.GetWidth(), view.GetHeight()));
@@ -637,7 +630,7 @@ void show_preload() {
 int engine_init_sprites() {
 	Debug::Printf(kDbgMsg_Info, "Initialize sprites");
 
-	HError err = spriteset.InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
+	HError err = _GP(spriteset).InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
 	if (!err) {
 		platform->FinishedUsingGraphicsMode();
 		allegro_exit();
@@ -657,26 +650,26 @@ void engine_init_game_settings() {
 
 	int ee;
 
-	for (ee = 0; ee < MAX_ROOM_OBJECTS + game.numcharacters; ee++)
+	for (ee = 0; ee < MAX_ROOM_OBJECTS + _GP(game).numcharacters; ee++)
 		actsps[ee] = nullptr;
 
 	for (ee = 0; ee < 256; ee++) {
-		if (game.paluses[ee] != PAL_BACKGROUND)
-			palette[ee] = game.defpal[ee];
+		if (_GP(game).paluses[ee] != PAL_BACKGROUND)
+			palette[ee] = _GP(game).defpal[ee];
 	}
 
-	for (ee = 0; ee < game.numcursors; ee++) {
+	for (ee = 0; ee < _GP(game).numcursors; ee++) {
 		// The cursor graphics are assigned to _G(mousecurs)[] and so cannot
 		// be removed from memory
-		if (game.mcurs[ee].pic >= 0)
-			spriteset.Precache(game.mcurs[ee].pic);
+		if (_GP(game).mcurs[ee].pic >= 0)
+			_GP(spriteset).Precache(_GP(game).mcurs[ee].pic);
 
 		// just in case they typed an invalid view number in the editor
-		if (game.mcurs[ee].view >= game.numviews)
-			game.mcurs[ee].view = -1;
+		if (_GP(game).mcurs[ee].view >= _GP(game).numviews)
+			_GP(game).mcurs[ee].view = -1;
 
-		if (game.mcurs[ee].view >= 0)
-			precache_view(game.mcurs[ee].view);
+		if (_GP(game).mcurs[ee].view >= 0)
+			precache_view(_GP(game).mcurs[ee].view);
 	}
 	// may as well preload the character gfx
 	if (playerchar->view >= 0)
@@ -690,8 +683,8 @@ void engine_init_game_settings() {
 	dummyguicontrol.objn = -1;*/
 
 	our_eip = -6;
-	//  game.chars[0].talkview=4;
-	//init_language_text(game.langcodes[0]);
+	//  _GP(game).chars[0].talkview=4;
+	//init_language_text(_GP(game).langcodes[0]);
 
 	for (ee = 0; ee < MAX_ROOM_OBJECTS; ee++) {
 		scrObj[ee].id = ee;
@@ -699,25 +692,25 @@ void engine_init_game_settings() {
 		// scrObj[ee].obj = NULL;
 	}
 
-	for (ee = 0; ee < game.numcharacters; ee++) {
-		memset(&game.chars[ee].inv[0], 0, MAX_INV * sizeof(short));
-		game.chars[ee].activeinv = -1;
-		game.chars[ee].following = -1;
-		game.chars[ee].followinfo = 97 | (10 << 8);
-		game.chars[ee].idletime = 20; // can be overridden later with SetIdle or summink
-		game.chars[ee].idleleft = game.chars[ee].idletime;
-		game.chars[ee].transparency = 0;
-		game.chars[ee].baseline = -1;
-		game.chars[ee].walkwaitcounter = 0;
-		game.chars[ee].z = 0;
+	for (ee = 0; ee < _GP(game).numcharacters; ee++) {
+		memset(&_GP(game).chars[ee].inv[0], 0, MAX_INV * sizeof(short));
+		_GP(game).chars[ee].activeinv = -1;
+		_GP(game).chars[ee].following = -1;
+		_GP(game).chars[ee].followinfo = 97 | (10 << 8);
+		_GP(game).chars[ee].idletime = 20; // can be overridden later with SetIdle or summink
+		_GP(game).chars[ee].idleleft = _GP(game).chars[ee].idletime;
+		_GP(game).chars[ee].transparency = 0;
+		_GP(game).chars[ee].baseline = -1;
+		_GP(game).chars[ee].walkwaitcounter = 0;
+		_GP(game).chars[ee].z = 0;
 		charextra[ee].xwas = INVALID_X;
 		charextra[ee].zoom = 100;
-		if (game.chars[ee].view >= 0) {
+		if (_GP(game).chars[ee].view >= 0) {
 			// set initial loop to 0
-			game.chars[ee].loop = 0;
+			_GP(game).chars[ee].loop = 0;
 			// or to 1 if they don't have up/down frames
-			if (views[game.chars[ee].view].loops[0].numFrames < 1)
-				game.chars[ee].loop = 1;
+			if (views[_GP(game).chars[ee].view].loops[0].numFrames < 1)
+				_GP(game).chars[ee].loop = 1;
 		}
 		charextra[ee].process_idle_this_time = 0;
 		charextra[ee].invorder_count = 0;
@@ -725,34 +718,34 @@ void engine_init_game_settings() {
 		charextra[ee].animwait = 0;
 	}
 	// multiply up gui positions
-	guibg = (Bitmap **)malloc(sizeof(Bitmap *) * game.numgui);
-	guibgbmp = (IDriverDependantBitmap **)malloc(sizeof(IDriverDependantBitmap *) * game.numgui);
-	for (ee = 0; ee < game.numgui; ee++) {
+	guibg = (Bitmap **)malloc(sizeof(Bitmap *) * _GP(game).numgui);
+	guibgbmp = (IDriverDependantBitmap **)malloc(sizeof(IDriverDependantBitmap *) * _GP(game).numgui);
+	for (ee = 0; ee < _GP(game).numgui; ee++) {
 		guibg[ee] = nullptr;
 		guibgbmp[ee] = nullptr;
 	}
 
 	our_eip = -5;
-	for (ee = 0; ee < game.numinvitems; ee++) {
-		if (game.invinfo[ee].flags & IFLG_STARTWITH) playerchar->inv[ee] = 1;
+	for (ee = 0; ee < _GP(game).numinvitems; ee++) {
+		if (_GP(game).invinfo[ee].flags & IFLG_STARTWITH) playerchar->inv[ee] = 1;
 		else playerchar->inv[ee] = 0;
 	}
 	play.score = 0;
 	play.sierra_inv_color = 7;
 	// copy the value set by the editor
-	if (game.options[OPT_GLOBALTALKANIMSPD] >= 0) {
-		play.talkanim_speed = game.options[OPT_GLOBALTALKANIMSPD];
-		game.options[OPT_GLOBALTALKANIMSPD] = 1;
+	if (_GP(game).options[OPT_GLOBALTALKANIMSPD] >= 0) {
+		play.talkanim_speed = _GP(game).options[OPT_GLOBALTALKANIMSPD];
+		_GP(game).options[OPT_GLOBALTALKANIMSPD] = 1;
 	} else {
-		play.talkanim_speed = -game.options[OPT_GLOBALTALKANIMSPD] - 1;
-		game.options[OPT_GLOBALTALKANIMSPD] = 0;
+		play.talkanim_speed = -_GP(game).options[OPT_GLOBALTALKANIMSPD] - 1;
+		_GP(game).options[OPT_GLOBALTALKANIMSPD] = 0;
 	}
 	play.inv_item_wid = 40;
 	play.inv_item_hit = 22;
 	play.messagetime = -1;
 	play.disabled_user_interface = 0;
 	play.gscript_timer = -1;
-	play.debug_mode = game.options[OPT_DEBUGMODE];
+	play.debug_mode = _GP(game).options[OPT_DEBUGMODE];
 	play.inv_top = 0;
 	play.inv_numdisp = 0;
 	play.obsolete_inv_numorder = 0;
@@ -769,7 +762,7 @@ void engine_init_game_settings() {
 	play.text_speed_modifier = 0;
 	play.text_align = kHAlignLeft;
 	// Make the default alignment to the right with right-to-left text
-	if (game.options[OPT_RIGHTLEFTWRITE])
+	if (_GP(game).options[OPT_RIGHTLEFTWRITE])
 		play.text_align = kHAlignRight;
 
 	play.speech_bubble_width = get_fixed_pixel_size(100);
@@ -799,7 +792,7 @@ void engine_init_game_settings() {
 	play.music_master_volume = 100 + LegacyMusicMasterVolumeAdjustment;
 	play.digital_master_volume = 100;
 	play.screen_flipped = 0;
-	play.cant_skip_speech = user_to_internal_skip_speech((SkipSpeechStyle)game.options[OPT_NOSKIPTEXT]);
+	play.cant_skip_speech = user_to_internal_skip_speech((SkipSpeechStyle)_GP(game).options[OPT_NOSKIPTEXT]);
 	play.sound_volume = 255;
 	play.speech_volume = 255;
 	play.normal_font = 0;
@@ -815,7 +808,7 @@ void engine_init_game_settings() {
 	play.no_multiloop_repeat = 0;
 	play.in_cutscene = 0;
 	play.fast_forward = 0;
-	play.totalscore = game.totalscore;
+	play.totalscore = _GP(game).totalscore;
 	play.roomscript_finished = 0;
 	play.no_textbg_when_voice = 0;
 	play.max_dialogoption_width = get_fixed_pixel_size(180);
@@ -862,12 +855,12 @@ void engine_init_game_settings() {
 	play.speech_has_voice = false;
 	play.speech_voice_blocking = false;
 	play.speech_in_post_state = false;
-	play.narrator_speech = game.playercharacter;
+	play.narrator_speech = _GP(game).playercharacter;
 	play.crossfading_out_channel = 0;
-	play.speech_textwindow_gui = game.options[OPT_TWCUSTOM];
+	play.speech_textwindow_gui = _GP(game).options[OPT_TWCUSTOM];
 	if (play.speech_textwindow_gui == 0)
 		play.speech_textwindow_gui = -1;
-	strcpy(play.game_name, game.gamename);
+	strcpy(play.game_name, _GP(game).gamename);
 	play.lastParserEntry[0] = 0;
 	play.follow_change_room_timer = 150;
 	for (ee = 0; ee < MAX_ROOM_BGFRAMES; ee++)
@@ -875,7 +868,7 @@ void engine_init_game_settings() {
 	play.game_speed_modifier = 0;
 	if (debug_flags & DBG_DEBUGMODE)
 		play.debug_mode = 1;
-	gui_disabled_style = convert_gui_disabled_style(game.options[OPT_DISABLEOFF]);
+	gui_disabled_style = convert_gui_disabled_style(_GP(game).options[OPT_DISABLEOFF]);
 	play.shake_screen_yoff = 0;
 
 	memset(&play.walkable_areas_on[0], 1, MAX_WALK_AREAS + 1);
@@ -902,8 +895,8 @@ void engine_init_game_settings() {
 	// We use same variable to read config and be used at runtime for now,
 	// so update it here with regards to game design option
 	usetup.RenderAtScreenRes =
-	    (game.options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_UserDefined && usetup.RenderAtScreenRes) ||
-	    game.options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_Enabled;
+	    (_GP(game).options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_UserDefined && usetup.RenderAtScreenRes) ||
+	    _GP(game).options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_Enabled;
 }
 
 void engine_setup_scsystem_auxiliary() {
@@ -1071,14 +1064,14 @@ void engine_prepare_config(ConfigTree &cfg, const String &exe_path, const Config
 
 	// Add "meta" config settings to let setup application(s)
 	// display correct properties to the user
-	INIwriteint(cfg, "misc", "defaultres", game.GetResolutionType());
-	INIwriteint(cfg, "misc", "letterbox", game.options[OPT_LETTERBOX]);
-	INIwriteint(cfg, "misc", "game_width", game.GetDefaultRes().Width);
-	INIwriteint(cfg, "misc", "game_height", game.GetDefaultRes().Height);
-	INIwriteint(cfg, "misc", "gamecolordepth", game.color_depth * 8);
-	if (game.options[OPT_RENDERATSCREENRES] != kRenderAtScreenRes_UserDefined) {
+	INIwriteint(cfg, "misc", "defaultres", _GP(game).GetResolutionType());
+	INIwriteint(cfg, "misc", "letterbox", _GP(game).options[OPT_LETTERBOX]);
+	INIwriteint(cfg, "misc", "game_width", _GP(game).GetDefaultRes().Width);
+	INIwriteint(cfg, "misc", "game_height", _GP(game).GetDefaultRes().Height);
+	INIwriteint(cfg, "misc", "gamecolordepth", _GP(game).color_depth * 8);
+	if (_GP(game).options[OPT_RENDERATSCREENRES] != kRenderAtScreenRes_UserDefined) {
 		// force enabled/disabled
-		INIwriteint(cfg, "graphics", "render_at_screenres", game.options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_Enabled);
+		INIwriteint(cfg, "graphics", "render_at_screenres", _GP(game).options[OPT_RENDERATSCREENRES] == kRenderAtScreenRes_Enabled);
 		INIwriteint(cfg, "disabled", "render_at_screenres", 1);
 	}
 }
@@ -1129,9 +1122,9 @@ static void engine_print_info(const std::set<String> &keys, const String &exe_pa
 		}
 	}
 	if (all || keys.count("data") > 0) {
-		data["data"]["gamename"] = game.gamename;
+		data["data"]["gamename"] = _GP(game).gamename;
 		data["data"]["version"] = String::FromFormat("%d", loaded_game_file_version);
-		data["data"]["compiledwith"] = game.compiled_with;
+		data["data"]["compiledwith"] = _GP(game).compiled_with;
 		data["data"]["basepack"] = usetup.main_data_filepath;
 	}
 	String full;
@@ -1275,7 +1268,7 @@ int initialize_engine(const ConfigTree &startup_opts) {
 
 	our_eip = -179;
 
-	engine_init_resolution_settings(game.GetGameRes());
+	engine_init_resolution_settings(_GP(game).GetGameRes());
 
 	// Attempt to initialize graphics mode
 	if (!engine_try_set_gfxmode_any(usetup.Screen))
@@ -1308,7 +1301,7 @@ bool engine_try_set_gfxmode_any(const ScreenSetup &setup) {
 	engine_shutdown_gfxmode();
 
 	const Size init_desktop = get_desktop_size();
-	if (!graphics_mode_init_any(game.GetGameRes(), setup, ColorDepthOption(game.GetColorDepth())))
+	if (!graphics_mode_init_any(_GP(game).GetGameRes(), setup, ColorDepthOption(_GP(game).GetColorDepth())))
 		return false;
 
 	engine_post_gfxmode_setup(init_desktop);
@@ -1342,7 +1335,7 @@ bool engine_try_switch_windowed_gfxmode() {
 		DisplayModeSetup dm_setup = usetup.Screen.DisplayMode;
 		dm_setup.Windowed = !old_dm.Windowed;
 		graphics_mode_get_defaults(dm_setup.Windowed, dm_setup.ScreenSize, use_frame_setup);
-		res = graphics_mode_set_dm_any(game.GetGameRes(), dm_setup, old_dm.ColorDepth, use_frame_setup);
+		res = graphics_mode_set_dm_any(_GP(game).GetGameRes(), dm_setup, old_dm.ColorDepth, use_frame_setup);
 	}
 
 	// Apply corresponding frame render method
diff --git a/engines/ags/engine/main/engine_setup.cpp b/engines/ags/engine/main/engine_setup.cpp
index 72a46c96c6..2e86041a01 100644
--- a/engines/ags/engine/main/engine_setup.cpp
+++ b/engines/ags/engine/main/engine_setup.cpp
@@ -43,13 +43,14 @@
 #include "ags/engine/main/engine_setup.h"
 #include "ags/engine/media/video/video.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
+
 extern ScriptSystem scsystem;
 extern int _places_r, _places_g, _places_b;
 extern IGraphicsDriver *gfxDriver;
@@ -62,18 +63,18 @@ void convert_gui_to_game_resolution(GameDataVersion filever) {
 	if (filever > kGameVersion_310)
 		return;
 
-	const int mul = game.GetDataUpscaleMult();
-	for (int i = 0; i < game.numcursors; ++i) {
-		game.mcurs[i].hotx *= mul;
-		game.mcurs[i].hoty *= mul;
+	const int mul = _GP(game).GetDataUpscaleMult();
+	for (int i = 0; i < _GP(game).numcursors; ++i) {
+		_GP(game).mcurs[i].hotx *= mul;
+		_GP(game).mcurs[i].hoty *= mul;
 	}
 
-	for (int i = 0; i < game.numinvitems; ++i) {
-		game.invinfo[i].hotx *= mul;
-		game.invinfo[i].hoty *= mul;
+	for (int i = 0; i < _GP(game).numinvitems; ++i) {
+		_GP(game).invinfo[i].hotx *= mul;
+		_GP(game).invinfo[i].hoty *= mul;
 	}
 
-	for (int i = 0; i < game.numgui; ++i) {
+	for (int i = 0; i < _GP(game).numgui; ++i) {
 		GUIMain *cgp = &guis[i];
 		cgp->X *= mul;
 		cgp->Y *= mul;
@@ -82,8 +83,8 @@ void convert_gui_to_game_resolution(GameDataVersion filever) {
 		if (cgp->Height < 1)
 			cgp->Height = 1;
 		// This is probably a way to fix GUIs meant to be covering whole screen
-		if (cgp->Width == game.GetDataRes().Width - 1)
-			cgp->Width = game.GetDataRes().Width;
+		if (cgp->Width == _GP(game).GetDataRes().Width - 1)
+			cgp->Width = _GP(game).GetDataRes().Width;
 
 		cgp->Width *= mul;
 		cgp->Height *= mul;
@@ -105,13 +106,13 @@ void convert_gui_to_game_resolution(GameDataVersion filever) {
 // Convert certain coordinates to data resolution (only if it's different from game resolution).
 // Necessary for 3.1.0 and above games with legacy "low-res coordinates" setting.
 void convert_objects_to_data_resolution(GameDataVersion filever) {
-	if (filever < kGameVersion_310 || game.GetDataUpscaleMult() == 1)
+	if (filever < kGameVersion_310 || _GP(game).GetDataUpscaleMult() == 1)
 		return;
 
-	const int mul = game.GetDataUpscaleMult();
-	for (int i = 0; i < game.numcharacters; ++i) {
-		game.chars[i].x /= mul;
-		game.chars[i].y /= mul;
+	const int mul = _GP(game).GetDataUpscaleMult();
+	for (int i = 0; i < _GP(game).numcharacters; ++i) {
+		_GP(game).chars[i].x /= mul;
+		_GP(game).chars[i].y /= mul;
 	}
 
 	for (int i = 0; i < numguiinv; ++i) {
@@ -122,8 +123,8 @@ void convert_objects_to_data_resolution(GameDataVersion filever) {
 }
 
 void engine_setup_system_gamesize() {
-	scsystem.width = game.GetGameRes().Width;
-	scsystem.height = game.GetGameRes().Height;
+	scsystem.width = _GP(game).GetGameRes().Width;
+	scsystem.height = _GP(game).GetGameRes().Height;
 	scsystem.viewport_width = game_to_data_coord(play.GetMainViewport().GetWidth());
 	scsystem.viewport_height = game_to_data_coord(play.GetMainViewport().GetHeight());
 }
@@ -132,8 +133,8 @@ void engine_init_resolution_settings(const Size game_size) {
 	Debug::Printf("Initializing resolution settings");
 	usetup.textheight = getfontheight_outlined(0) + 1;
 
-	Debug::Printf(kDbgMsg_Info, "Game native resolution: %d x %d (%d bit)%s", game_size.Width, game_size.Height, game.color_depth * 8,
-		game.IsLegacyLetterbox() ? " letterbox-by-design" : "");
+	Debug::Printf(kDbgMsg_Info, "Game native resolution: %d x %d (%d bit)%s", game_size.Width, game_size.Height, _GP(game).color_depth * 8,
+		_GP(game).IsLegacyLetterbox() ? " letterbox-by-design" : "");
 
 	convert_gui_to_game_resolution(loaded_game_file_version);
 	convert_objects_to_data_resolution(loaded_game_file_version);
diff --git a/engines/ags/engine/main/engine_setup.h b/engines/ags/engine/main/engine_setup.h
index cc20398114..19052e7955 100644
--- a/engines/ags/engine/main/engine_setup.h
+++ b/engines/ags/engine/main/engine_setup.h
@@ -28,7 +28,7 @@
 
 namespace AGS3 {
 
-// Sets up game viewport and object scaling parameters depending on game.
+// Sets up game viewport and object scaling parameters depending on _GP(game).
 // TODO: this is part of the game init, not engine init, move it later
 void engine_init_resolution_settings(const Size game_size);
 // Setup engine after the graphics mode has changed
diff --git a/engines/ags/engine/main/game_file.cpp b/engines/ags/engine/main/game_file.cpp
index 000949b621..e6ae7bcf56 100644
--- a/engines/ags/engine/main/game_file.cpp
+++ b/engines/ags/engine/main/game_file.cpp
@@ -52,6 +52,7 @@
 #include "ags/engine/game/game_init.h"
 #include "ags/plugins/agsplugin.h"
 #include "ags/engine/script/script.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -60,7 +61,7 @@ using namespace AGS::Engine;
 
 extern int ifacepopped;
 
-extern GameSetupStruct game;
+
 extern ViewStruct *views;
 extern DialogTopic *dialog;
 
@@ -117,11 +118,11 @@ HGameFileError game_file_first_open(MainGameSource &src) {
 
 void PreReadSaveFileInfo(Stream *in, GameDataVersion data_ver) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
-	game.ReadFromFile(&align_s);
+	_GP(game).ReadFromFile(&align_s);
 	// Discard game messages we do not need here
-	delete[] game.load_messages;
-	game.load_messages = nullptr;
-	game.read_savegame_info(in, data_ver);
+	delete[] _GP(game).load_messages;
+	_GP(game).load_messages = nullptr;
+	_GP(game).read_savegame_info(in, data_ver);
 }
 
 HError preload_game_data() {
@@ -131,14 +132,14 @@ HError preload_game_data() {
 		return (HError)err;
 	// Read only the particular data we need for preliminary game analysis
 	PreReadSaveFileInfo(src.InputStream.get(), src.DataVersion);
-	game.compiled_with = src.CompiledWith;
-	FixupSaveDirectory(game);
+	_GP(game).compiled_with = src.CompiledWith;
+	FixupSaveDirectory(_GP(game));
 	return HError::None();
 }
 
 HError load_game_file() {
 	MainGameSource src;
-	LoadedGameEntities ents(game, dialog, views);
+	LoadedGameEntities ents(_GP(game), dialog, views);
 	HGameFileError load_err = OpenMainGameFileFromDefaultAsset(src);
 	if (load_err) {
 		load_err = ReadGameData(ents, src.InputStream.get(), src.DataVersion);
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index 3488225ffe..f53af57d99 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -66,7 +66,7 @@
 #include "ags/engine/ac/timer.h"
 #include "ags/engine/ac/keycode.h"
 #include "ags/lib/allegro/keyboard.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/events.h"
 
 namespace AGS3 {
@@ -80,7 +80,7 @@ extern int ifacepopped;
 extern int is_text_overlay;
 extern int proper_exit, our_eip;
 extern int displayed_room, starting_room, in_new_room, new_room_was;
-extern GameSetupStruct game;
+
 extern RoomStruct thisroom;
 extern int game_paused;
 extern int getloctype_index;
@@ -96,7 +96,7 @@ extern RoomObject *objs;
 extern char noWalkBehindsAtAll;
 extern RoomStatus *croom;
 extern CharacterExtras *charextra;
-extern SpriteCache spriteset;
+
 extern int cur_mode, cur_cursor;
 
 // Checks if user interface should remain disabled for now
@@ -435,18 +435,18 @@ static void check_keyboard_controls() {
 			sprintf(&infobuf[strlen(infobuf)],
 				"[Object %d: (%d,%d) size (%d x %d) on:%d moving:%s animating:%d slot:%d trnsp:%d clkble:%d",
 				ff, objs[ff].x, objs[ff].y,
-				(spriteset[objs[ff].num] != nullptr) ? game.SpriteInfos[objs[ff].num].Width : 0,
-				(spriteset[objs[ff].num] != nullptr) ? game.SpriteInfos[objs[ff].num].Height : 0,
+				(_GP(spriteset)[objs[ff].num] != nullptr) ? _GP(game).SpriteInfos[objs[ff].num].Width : 0,
+				(_GP(spriteset)[objs[ff].num] != nullptr) ? _GP(game).SpriteInfos[objs[ff].num].Height : 0,
 				objs[ff].on,
 				(objs[ff].moving > 0) ? "yes" : "no", objs[ff].cycling,
 				objs[ff].num, objs[ff].transparent,
 				((objs[ff].flags & OBJF_NOINTERACT) != 0) ? 0 : 1);
 		}
 		Display(infobuf);
-		int chd = game.playercharacter;
+		int chd = _GP(game).playercharacter;
 		char bigbuffer[STD_BUFFER_SIZE] = "CHARACTERS IN THIS ROOM:[";
-		for (ff = 0; ff < game.numcharacters; ff++) {
-			if (game.chars[ff].room != displayed_room) continue;
+		for (ff = 0; ff < _GP(game).numcharacters; ff++) {
+			if (_GP(game).chars[ff].room != displayed_room) continue;
 			if (strlen(bigbuffer) > 430) {
 				strcat(bigbuffer, "and more...");
 				Display(bigbuffer);
@@ -455,11 +455,11 @@ static void check_keyboard_controls() {
 			chd = ff;
 			sprintf(&bigbuffer[strlen(bigbuffer)],
 				"%s (view/loop/frm:%d,%d,%d  x/y/z:%d,%d,%d  idleview:%d,time:%d,left:%d walk:%d anim:%d follow:%d flags:%X wait:%d zoom:%d)[",
-				game.chars[chd].scrname, game.chars[chd].view + 1, game.chars[chd].loop, game.chars[chd].frame,
-				game.chars[chd].x, game.chars[chd].y, game.chars[chd].z,
-				game.chars[chd].idleview, game.chars[chd].idletime, game.chars[chd].idleleft,
-				game.chars[chd].walking, game.chars[chd].animating, game.chars[chd].following,
-				game.chars[chd].flags, game.chars[chd].wait, charextra[chd].zoom);
+				_GP(game).chars[chd].scrname, _GP(game).chars[chd].view + 1, _GP(game).chars[chd].loop, _GP(game).chars[chd].frame,
+				_GP(game).chars[chd].x, _GP(game).chars[chd].y, _GP(game).chars[chd].z,
+				_GP(game).chars[chd].idleview, _GP(game).chars[chd].idletime, _GP(game).chars[chd].idleleft,
+				_GP(game).chars[chd].walking, _GP(game).chars[chd].animating, _GP(game).chars[chd].following,
+				_GP(game).chars[chd].flags, _GP(game).chars[chd].wait, charextra[chd].zoom);
 		}
 		Display(bigbuffer);
 
@@ -498,7 +498,7 @@ static void check_keyboard_controls() {
 	// extended keys (eg. up/down arrow; 256+)
 	if ((((kgn >= 32) && (kgn <= 255) && (kgn != '[')) || (kgn == eAGSKeyCodeReturn) || (kgn == eAGSKeyCodeBackspace))
 		&& !all_buttons_disabled) {
-		for (int guiIndex = 0; guiIndex < game.numgui; guiIndex++) {
+		for (int guiIndex = 0; guiIndex < _GP(game).numgui; guiIndex++) {
 			auto &gui = guis[guiIndex];
 
 			if (!gui.IsDisplayed()) continue;
@@ -745,7 +745,7 @@ void UpdateGameOnce(bool checkControls, IDriverDependantBitmap *extraBitmap, int
 	game_loop_check_problems_at_start();
 
 	// if we're not fading in, don't count the fadeouts
-	if ((play.no_hicolor_fadein) && (game.options[OPT_FADETYPE] == FADE_NORMAL))
+	if ((play.no_hicolor_fadein) && (_GP(game).options[OPT_FADETYPE] == FADE_NORMAL))
 		play.screen_is_faded_out = 0;
 
 	our_eip = 1014;
@@ -987,7 +987,7 @@ void GameLoopUntilNoOverlay() {
 
 extern unsigned int load_new_game;
 void RunGameUntilAborted() {
-	// skip ticks to account for time spent starting game.
+	// skip ticks to account for time spent starting _GP(game).
 	skipMissedTicks();
 
 	while (!_G(abort_engine)) {
diff --git a/engines/ags/engine/main/game_start.cpp b/engines/ags/engine/main/game_start.cpp
index d12ca06d13..a95dd4a806 100644
--- a/engines/ags/engine/main/game_start.cpp
+++ b/engines/ags/engine/main/game_start.cpp
@@ -44,7 +44,7 @@
 #include "ags/engine/script/script.h"
 #include "ags/engine/media/audio/audio_system.h"
 #include "ags/engine/ac/timer.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -53,7 +53,7 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern int our_eip, displayed_room;
-extern GameSetupStruct game;
+
 extern GameState play;
 extern std::vector<ccInstance *> moduleInst;
 extern int numScriptModules;
@@ -89,7 +89,7 @@ void start_game() {
 
 	our_eip = -42;
 
-	// skip ticks to account for initialisation or a restored game.
+	// skip ticks to account for initialisation or a restored _GP(game).
 	skipMissedTicks();
 
 	for (int kk = 0; kk < numScriptModules; kk++)
@@ -127,11 +127,11 @@ void initialize_start_and_play_game(int override_start_room, int loadSaveOnStart
 		if (convert_16bit_bgr) {
 			// Disable text as speech while displaying the warning message
 			// This happens if the user's graphics card does BGR order 16-bit colour
-			int oldalways = game.options[OPT_ALWAYSSPCH];
-			game.options[OPT_ALWAYSSPCH] = 0;
+			int oldalways = _GP(game).options[OPT_ALWAYSSPCH];
+			_GP(game).options[OPT_ALWAYSSPCH] = 0;
 			// PSP: This is normal. Don't show a warning.
-			//Display ("WARNING: AGS has detected that you have an incompatible graphics card for this game. You may experience colour problems during the game. Try running the game with \"--15bit\" command line parameter and see if that helps.[[Click the mouse to continue.");
-			game.options[OPT_ALWAYSSPCH] = oldalways;
+			//Display ("WARNING: AGS has detected that you have an incompatible graphics card for this _GP(game). You may experience colour problems during the _GP(game). Try running the game with \"--15bit\" command line parameter and see if that helps.[[Click the mouse to continue.");
+			_GP(game).options[OPT_ALWAYSSPCH] = oldalways;
 		}
 
 		::AGS::g_vm->setRandomNumberSeed(play.randseed);
diff --git a/engines/ags/engine/main/graphics_mode.cpp b/engines/ags/engine/main/graphics_mode.cpp
index 90120f1326..f568f4f412 100644
--- a/engines/ags/engine/main/graphics_mode.cpp
+++ b/engines/ags/engine/main/graphics_mode.cpp
@@ -38,7 +38,7 @@
 #include "ags/engine/main/graphics_mode.h"
 #include "ags/engine/main/main_allegro.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/main/quit.cpp b/engines/ags/engine/main/quit.cpp
index c262b7fecf..a7e0e3bd84 100644
--- a/engines/ags/engine/main/quit.cpp
+++ b/engines/ags/engine/main/quit.cpp
@@ -46,7 +46,7 @@
 #include "ags/shared/core/assetmanager.h"
 #include "ags/plugins/plugin_engine.h"
 #include "ags/engine/media/audio/audio_system.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -54,8 +54,8 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
-extern SpriteCache spriteset;
+
+
 extern RoomStruct thisroom;
 extern RoomStatus troom;    // used for non-saveable rooms, eg. intro
 extern int our_eip;
@@ -91,11 +91,11 @@ void quit_shutdown_scripts() {
 
 void quit_check_dynamic_sprites(QuitReason qreason) {
 	if ((qreason & kQuitKind_NormalExit) && (check_dynamic_sprites_at_exit) &&
-		(game.options[OPT_DEBUGMODE] != 0)) {
+		(_GP(game).options[OPT_DEBUGMODE] != 0)) {
 		// game exiting normally -- make sure the dynamic sprites
 		// have been deleted
-		for (int i = 1; i < spriteset.GetSpriteSlotCount(); i++) {
-			if (game.SpriteInfos[i].Flags & SPF_DYNAMICALLOC)
+		for (int i = 1; i < _GP(spriteset).GetSpriteSlotCount(); i++) {
+			if (_GP(game).SpriteInfos[i].Flags & SPF_DYNAMICALLOC)
 				debug_script_warn("Dynamic sprite %d was never deleted", i);
 		}
 	}
@@ -120,7 +120,7 @@ void quit_shutdown_platform(QuitReason qreason) {
 
 void quit_shutdown_audio() {
 	our_eip = 9917;
-	game.options[OPT_CROSSFADEMUSIC] = 0;
+	_GP(game).options[OPT_CROSSFADEMUSIC] = 0;
 	shutdown_sound();
 }
 
@@ -259,7 +259,7 @@ void quit_free() {
 	shutdown_font_renderer();
 	our_eip = 9902;
 
-	spriteset.Reset();
+	_GP(spriteset).Reset();
 
 	our_eip = 9907;
 
diff --git a/engines/ags/engine/main/update.cpp b/engines/ags/engine/main/update.cpp
index 65a67b5034..ebbfc07b73 100644
--- a/engines/ags/engine/main/update.cpp
+++ b/engines/ags/engine/main/update.cpp
@@ -24,7 +24,6 @@
 // Game update procedure
 //
 
-//include <math.h>
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/character.h"
 #include "ags/engine/ac/characterextras.h"
@@ -48,6 +47,7 @@
 #include "ags/engine/ac/timer.h"
 #include "ags/engine/main/game_run.h"
 #include "ags/engine/ac/movelist.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -56,7 +56,7 @@ using namespace AGS::Engine;
 
 extern MoveList *mls;
 extern RoomStatus *croom;
-extern GameSetupStruct game;
+
 extern GameState play;
 extern RoomStruct thisroom;
 extern RoomObject *objs;
@@ -210,7 +210,7 @@ void update_cycling_views() {
 
 void update_shadow_areas() {
 	// shadow areas
-	int onwalkarea = get_walkable_area_at_character(game.playercharacter);
+	int onwalkarea = get_walkable_area_at_character(_GP(game).playercharacter);
 	if (onwalkarea < 0);
 	else if (playerchar->flags & CHF_FIXVIEW);
 	else {
@@ -223,10 +223,10 @@ void update_shadow_areas() {
 
 void update_character_move_and_anim(int &numSheep, int *followingAsSheep) {
 	// move & animate characters
-	for (int aa = 0; aa < game.numcharacters; aa++) {
-		if (game.chars[aa].on != 1) continue;
+	for (int aa = 0; aa < _GP(game).numcharacters; aa++) {
+		if (_GP(game).chars[aa].on != 1) continue;
 
-		CharacterInfo *chi = &game.chars[aa];
+		CharacterInfo *chi = &_GP(game).chars[aa];
 		CharacterExtras *chex = &charextra[aa];
 
 		chi->UpdateMoveAndAnim(aa, chex, numSheep, followingAsSheep);
@@ -236,7 +236,7 @@ void update_character_move_and_anim(int &numSheep, int *followingAsSheep) {
 void update_following_exactly_characters(int &numSheep, int *followingAsSheep) {
 	// update location of all following_exactly characters
 	for (int aa = 0; aa < numSheep; aa++) {
-		CharacterInfo *chi = &game.chars[followingAsSheep[aa]];
+		CharacterInfo *chi = &_GP(game).chars[followingAsSheep[aa]];
 
 		chi->UpdateFollowingExactlyCharacter();
 	}
@@ -340,7 +340,7 @@ void update_sierra_speech() {
 					((curLipLinePhoneme < 0) || (voice_pos_ms >= splipsync[curLipLine].endtimeoffs[curLipLinePhoneme]))) {
 					curLipLinePhoneme++;
 					if (curLipLinePhoneme >= splipsync[curLipLine].numPhonemes)
-						facetalkframe = game.default_lipsync_frame;
+						facetalkframe = _GP(game).default_lipsync_frame;
 					else
 						facetalkframe = splipsync[curLipLine].frame[curLipLinePhoneme];
 
@@ -367,7 +367,7 @@ void update_sierra_speech() {
 					(play.close_mouth_speech_time > 0))) {
 				facetalkframe = 0;
 				facetalkwait = play.messagetime;
-			} else if ((game.options[OPT_LIPSYNCTEXT]) && (facetalkrepeat > 0)) {
+			} else if ((_GP(game).options[OPT_LIPSYNCTEXT]) && (facetalkrepeat > 0)) {
 				// lip-sync speech (and not a thought)
 				facetalkwait = update_lip_sync(facetalkview, facetalkloop, &facetalkframe);
 				// It is actually displayed for facetalkwait+1 loops
@@ -407,7 +407,7 @@ void update_sierra_speech() {
 			int view_frame_x = 0;
 			int view_frame_y = 0;
 
-			if (game.options[OPT_SPEECHTYPE] == 3) {
+			if (_GP(game).options[OPT_SPEECHTYPE] == 3) {
 				// QFG4-style fullscreen dialog
 				if (facetalk_qfg4_override_placement_x) {
 					view_frame_x = play.speech_portrait_x;
@@ -415,7 +415,7 @@ void update_sierra_speech() {
 				if (facetalk_qfg4_override_placement_y) {
 					view_frame_y = play.speech_portrait_y;
 				} else {
-					view_frame_y = (screenover[face_talking].pic->GetHeight() / 2) - (game.SpriteInfos[thisPic].Height / 2);
+					view_frame_y = (screenover[face_talking].pic->GetHeight() / 2) - (_GP(game).SpriteInfos[thisPic].Height / 2);
 				}
 				screenover[face_talking].pic->Clear(0);
 			} else {
@@ -424,12 +424,12 @@ void update_sierra_speech() {
 
 			Bitmap *frame_pic = screenover[face_talking].pic;
 			const ViewFrame *face_vf = &views[facetalkview].loops[facetalkloop].frames[facetalkframe];
-			bool face_has_alpha = (game.SpriteInfos[face_vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
+			bool face_has_alpha = (_GP(game).SpriteInfos[face_vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
 			DrawViewFrame(frame_pic, face_vf, view_frame_x, view_frame_y);
 
 			if ((facetalkchar->blinkview > 0) && (facetalkchar->blinktimer < 0)) {
 				ViewFrame *blink_vf = &views[facetalkchar->blinkview].loops[facetalkBlinkLoop].frames[facetalkchar->blinkframe];
-				face_has_alpha |= (game.SpriteInfos[blink_vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
+				face_has_alpha |= (_GP(game).SpriteInfos[blink_vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
 				// draw the blinking sprite on top
 				DrawViewFrame(frame_pic, blink_vf, view_frame_x, view_frame_y, face_has_alpha);
 			}
diff --git a/engines/ags/engine/media/audio/audio.cpp b/engines/ags/engine/media/audio/audio.cpp
index 1ef3500aaa..ecc64698a4 100644
--- a/engines/ags/engine/media/audio/audio.cpp
+++ b/engines/ags/engine/media/audio/audio.cpp
@@ -42,6 +42,7 @@
 #include "ags/shared/core/assetmanager.h"
 #include "ags/engine/ac/timer.h"
 #include "ags/engine/main/game_run.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -103,7 +104,7 @@ void set_clip_to_channel(int chanid, SOUNDCLIP *clip) {
 
 volatile bool _audio_doing_crossfade;
 
-extern GameSetupStruct game;
+
 extern GameSetup usetup;
 extern GameState play;
 extern RoomStruct thisroom;
@@ -117,8 +118,8 @@ int reserved_channel_count = 0;
 
 void calculate_reserved_channel_count() {
 	int reservedChannels = 0;
-	for (size_t i = 0; i < game.audioClipTypes.size(); i++) {
-		reservedChannels += game.audioClipTypes[i].reservedChannels;
+	for (size_t i = 0; i < _GP(game).audioClipTypes.size(); i++) {
+		reservedChannels += _GP(game).audioClipTypes[i].reservedChannels;
 	}
 	reserved_channel_count = reservedChannels;
 }
@@ -130,7 +131,7 @@ void update_clip_default_volume(ScriptAudioClip *audioClip) {
 }
 
 void start_fading_in_new_track_if_applicable(int fadeInChannel, ScriptAudioClip *newSound) {
-	int crossfadeSpeed = game.audioClipTypes[newSound->type].crossfadeSpeed;
+	int crossfadeSpeed = _GP(game).audioClipTypes[newSound->type].crossfadeSpeed;
 	if (crossfadeSpeed > 0) {
 		update_clip_default_volume(newSound);
 		play.crossfade_in_volume_per_step = crossfadeSpeed;
@@ -159,8 +160,8 @@ static void move_track_to_crossfade_channel(int currentChannel, int crossfadeSpe
 
 void stop_or_fade_out_channel(int fadeOutChannel, int fadeInChannel, ScriptAudioClip *newSound) {
 	ScriptAudioClip *sourceClip = AudioChannel_GetPlayingClip(&scrAudioChannel[fadeOutChannel]);
-	if ((sourceClip != nullptr) && (game.audioClipTypes[sourceClip->type].crossfadeSpeed > 0)) {
-		move_track_to_crossfade_channel(fadeOutChannel, game.audioClipTypes[sourceClip->type].crossfadeSpeed, fadeInChannel, newSound);
+	if ((sourceClip != nullptr) && (_GP(game).audioClipTypes[sourceClip->type].crossfadeSpeed > 0)) {
+		move_track_to_crossfade_channel(fadeOutChannel, _GP(game).audioClipTypes[sourceClip->type].crossfadeSpeed, fadeInChannel, newSound);
 	} else {
 		stop_and_destroy_channel(fadeOutChannel);
 	}
@@ -179,12 +180,12 @@ static int find_free_audio_channel(ScriptAudioClip *clip, int priority, bool int
 	int startAtChannel = reserved_channel_count;
 	int endBeforeChannel = MAX_SOUND_CHANNELS;
 
-	if (game.audioClipTypes[clip->type].reservedChannels > 0) {
+	if (_GP(game).audioClipTypes[clip->type].reservedChannels > 0) {
 		startAtChannel = 0;
 		for (int i = 0; i < clip->type; i++) {
-			startAtChannel += game.audioClipTypes[i].reservedChannels;
+			startAtChannel += _GP(game).audioClipTypes[i].reservedChannels;
 		}
-		endBeforeChannel = startAtChannel + game.audioClipTypes[clip->type].reservedChannels;
+		endBeforeChannel = startAtChannel + _GP(game).audioClipTypes[clip->type].reservedChannels;
 	}
 
 	for (int i = startAtChannel; i < endBeforeChannel; i++) {
@@ -294,7 +295,7 @@ static void audio_update_polled_stuff() {
 	// Do audio queue
 	if (play.new_music_queue_size > 0) {
 		for (int i = 0; i < play.new_music_queue_size; i++) {
-			ScriptAudioClip *clip = &game.audioClips[play.new_music_queue[i].audioClipIndex];
+			ScriptAudioClip *clip = &_GP(game).audioClips[play.new_music_queue[i].audioClipIndex];
 			int channel = find_free_audio_channel(clip, clip->defaultPriority, false);
 			if (channel >= 0) {
 				QueuedAudioItem itemToPlay = play.new_music_queue[i];
@@ -325,7 +326,7 @@ static void audio_update_polled_stuff() {
 // Applies a volume drop modifier to the clip, in accordance to its audio type
 static void apply_volume_drop_to_clip(SOUNDCLIP *clip) {
 	int audiotype = clip->_sourceClipType;
-	clip->apply_volume_modifier(-(game.audioClipTypes[audiotype].volume_reduction_while_speech_playing * 255 / 100));
+	clip->apply_volume_modifier(-(_GP(game).audioClipTypes[audiotype].volume_reduction_while_speech_playing * 255 / 100));
 }
 
 static void queue_audio_clip_to_play(ScriptAudioClip *clip, int priority, int repeat) {
@@ -372,7 +373,7 @@ ScriptAudioChannel *play_audio_clip_on_channel(int channel, ScriptAudioClip *cli
 		// disable the clip under condition that there's more than one
 		// channel for this audio type? It does not even check if
 		// anything of this type is currently playing.
-		if (game.audioClipTypes[clip->type].reservedChannels != 1)
+		if (_GP(game).audioClipTypes[clip->type].reservedChannels != 1)
 			soundfx->set_volume_percent(0);
 	}
 
@@ -399,7 +400,7 @@ ScriptAudioChannel *play_audio_clip_on_channel(int channel, ScriptAudioClip *cli
 void remove_clips_of_type_from_queue(int audioType) {
 	int aa;
 	for (aa = 0; aa < play.new_music_queue_size; aa++) {
-		ScriptAudioClip *clip = &game.audioClips[play.new_music_queue[aa].audioClipIndex];
+		ScriptAudioClip *clip = &_GP(game).audioClips[play.new_music_queue[aa].audioClipIndex];
 		if (clip->type == audioType) {
 			play.new_music_queue_size--;
 			for (int bb = aa; bb < play.new_music_queue_size; bb++)
@@ -414,7 +415,7 @@ void update_queued_clips_volume(int audioType, int new_vol) {
 		// NOTE: if clip is uncached, the volume will be set from defaults when it is loaded
 		SOUNDCLIP *sndclip = play.new_music_queue[i].cachedClip;
 		if (sndclip) {
-			ScriptAudioClip *clip = &game.audioClips[play.new_music_queue[i].audioClipIndex];
+			ScriptAudioClip *clip = &_GP(game).audioClips[play.new_music_queue[i].audioClipIndex];
 			if (clip->type == audioType)
 				sndclip->set_volume_percent(new_vol);
 		}
@@ -444,8 +445,8 @@ ScriptAudioChannel *play_audio_clip(ScriptAudioClip *clip, int priority, int rep
 }
 
 ScriptAudioChannel *play_audio_clip_by_index(int audioClipIndex) {
-	if ((audioClipIndex >= 0) && ((size_t)audioClipIndex < game.audioClips.size()))
-		return AudioClip_Play(&game.audioClips[audioClipIndex], SCR_NO_VALUE, SCR_NO_VALUE);
+	if ((audioClipIndex >= 0) && ((size_t)audioClipIndex < _GP(game).audioClips.size()))
+		return AudioClip_Play(&_GP(game).audioClips[audioClipIndex], SCR_NO_VALUE, SCR_NO_VALUE);
 	else
 		return nullptr;
 }
@@ -491,7 +492,7 @@ void stop_and_destroy_channel(int chid) {
 int get_old_style_number_for_sound(int sound_number) {
 	int audio_clip_id = 0;
 
-	if (game.IsLegacyAudioSystem()) {
+	if (_GP(game).IsLegacyAudioSystem()) {
 		// No sound assigned.
 		if (sound_number < 1)
 			return 0;
@@ -507,14 +508,14 @@ int get_old_style_number_for_sound(int sound_number) {
 
 	if (audio_clip_id >= 0) {
 		int old_style_number = 0;
-		if (sscanf(game.audioClips[audio_clip_id].scriptName.GetCStr(), "aSound%d", &old_style_number) == 1)
+		if (sscanf(_GP(game).audioClips[audio_clip_id].scriptName.GetCStr(), "aSound%d", &old_style_number) == 1)
 			return old_style_number;
 	}
 	return 0;
 }
 
 SOUNDCLIP *load_sound_clip_from_old_style_number(bool isMusic, int indexNumber, bool repeat) {
-	ScriptAudioClip *audioClip = GetAudioClipForOldStyleNumber(game, isMusic, indexNumber);
+	ScriptAudioClip *audioClip = GetAudioClipForOldStyleNumber(_GP(game), isMusic, indexNumber);
 
 	if (audioClip != nullptr) {
 		return load_sound_clip(audioClip, repeat);
@@ -843,7 +844,7 @@ void update_audio_system_on_game_loop() {
 			// The current music has finished
 			play.cur_music_number = -1;
 			play_next_queued();
-		} else if ((game.options[OPT_CROSSFADEMUSIC] > 0) &&
+		} else if ((_GP(game).options[OPT_CROSSFADEMUSIC] > 0) &&
 			(play.music_queue_size > 0) && (!crossFading)) {
 			// want to crossfade, and new tune in the queue
 			auto *ch = lock.GetChannel(SCHAN_MUSIC);
@@ -853,7 +854,7 @@ void update_audio_system_on_game_loop() {
 				if ((curpos > 0) && (muslen > 0)) {
 					// we want to crossfade, and we know how far through
 					// the tune we are
-					int takesSteps = calculate_max_volume() / game.options[OPT_CROSSFADEMUSIC];
+					int takesSteps = calculate_max_volume() / _GP(game).options[OPT_CROSSFADEMUSIC];
 					int takesMs = ::lround(takesSteps * 1000.0f / get_current_fps());
 					if (curpos >= muslen - takesMs)
 						play_next_queued();
@@ -876,14 +877,14 @@ void stopmusic() {
 		crossFading = -1;
 	} else if (crossFading < 0) {
 		// the music is already fading out
-		if (game.options[OPT_CROSSFADEMUSIC] <= 0) {
+		if (_GP(game).options[OPT_CROSSFADEMUSIC] <= 0) {
 			// If they have since disabled crossfading, stop the fadeout
 			stop_and_destroy_channel(SCHAN_MUSIC);
 			crossFading = 0;
 			crossFadeStep = 0;
 			update_music_volume();
 		}
-	} else if ((game.options[OPT_CROSSFADEMUSIC] > 0)
+	} else if ((_GP(game).options[OPT_CROSSFADEMUSIC] > 0)
 		&& (lock.GetChannelIfPlaying(SCHAN_MUSIC) != nullptr)
 		&& (current_music_type != 0)
 		&& (current_music_type != MUS_MIDI)
@@ -891,7 +892,7 @@ void stopmusic() {
 
 		crossFading = -1;
 		crossFadeStep = 0;
-		crossFadeVolumePerStep = game.options[OPT_CROSSFADEMUSIC];
+		crossFadeVolumePerStep = _GP(game).options[OPT_CROSSFADEMUSIC];
 		crossFadeVolumeAtStart = calculate_max_volume();
 	} else
 		stop_and_destroy_channel(SCHAN_MUSIC);
@@ -964,7 +965,7 @@ int prepare_for_new_music() {
 
 	int useChannel = SCHAN_MUSIC;
 
-	if ((game.options[OPT_CROSSFADEMUSIC] > 0)
+	if ((_GP(game).options[OPT_CROSSFADEMUSIC] > 0)
 		&& (lock.GetChannelIfPlaying(SCHAN_MUSIC) != nullptr)
 		&& (current_music_type != MUS_MIDI)
 		&& (current_music_type != MUS_MOD)) {
@@ -981,7 +982,7 @@ int prepare_for_new_music() {
 		} else {
 			// start crossfading
 			crossFadeStep = 0;
-			crossFadeVolumePerStep = game.options[OPT_CROSSFADEMUSIC];
+			crossFadeVolumePerStep = _GP(game).options[OPT_CROSSFADEMUSIC];
 			crossFadeVolumeAtStart = calculate_max_volume();
 		}
 		useChannel = SPECIAL_CROSSFADE_CHANNEL;
@@ -1004,7 +1005,7 @@ int prepare_for_new_music() {
 ScriptAudioClip *get_audio_clip_for_music(int mnum) {
 	if (mnum >= QUEUED_MUSIC_REPEAT)
 		mnum -= QUEUED_MUSIC_REPEAT;
-	return GetAudioClipForOldStyleNumber(game, true, mnum);
+	return GetAudioClipForOldStyleNumber(_GP(game), true, mnum);
 }
 
 SOUNDCLIP *load_music_from_disk(int mnum, bool doRepeat) {
diff --git a/engines/ags/engine/media/audio/soundcache.cpp b/engines/ags/engine/media/audio/soundcache.cpp
index 470cfd1a5f..65800f77dd 100644
--- a/engines/ags/engine/media/audio/soundcache.cpp
+++ b/engines/ags/engine/media/audio/soundcache.cpp
@@ -27,7 +27,7 @@
 #include "ags/engine/util/mutex_lock.h"
 #include "ags/shared/util/string.h"
 #include "ags/shared/debugging/out.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 #include "common/memstream.h"
 
diff --git a/engines/ags/engine/platform/linux/acpllnx.cpp b/engines/ags/engine/platform/linux/acpllnx.cpp
index f9a0706525..b9cdbaee22 100644
--- a/engines/ags/engine/platform/linux/acpllnx.cpp
+++ b/engines/ags/engine/platform/linux/acpllnx.cpp
@@ -157,7 +157,7 @@ unsigned long AGSLinux::GetDiskFreeSpaceMB() {
 }
 
 const char *AGSLinux::GetNoMouseErrorString() {
-	return "This game requires a mouse. You need to configure and setup your mouse to play this game.\n";
+	return "This game requires a mouse. You need to configure and setup your mouse to play this _GP(game).\n";
 }
 
 const char *AGSLinux::GetAllegroFailUserHint() {
diff --git a/engines/ags/engine/platform/windows/acplwin.cpp b/engines/ags/engine/platform/windows/acplwin.cpp
index 08aad2ad86..b01a694a10 100644
--- a/engines/ags/engine/platform/windows/acplwin.cpp
+++ b/engines/ags/engine/platform/windows/acplwin.cpp
@@ -53,7 +53,6 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern GameSetupStruct game;
 extern GameSetup usetup;
 extern int our_eip;
 extern IGraphicsDriver *gfxDriver;
diff --git a/engines/ags/engine/script/cc_instance.cpp b/engines/ags/engine/script/cc_instance.cpp
index 6a2a70a7cd..0d894775b1 100644
--- a/engines/ags/engine/script/cc_instance.cpp
+++ b/engines/ags/engine/script/cc_instance.cpp
@@ -43,7 +43,7 @@
 #include "ags/engine/ac/dynobj/cc_dynamicobject_addr_and_manager.h"
 #include "ags/shared/util/memory.h"
 #include "ags/shared/util/string_utils.h" // linux strnicmp definition
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/engine/script/script.cpp b/engines/ags/engine/script/script.cpp
index 67a35c374d..7ed756c82b 100644
--- a/engines/ags/engine/script/script.cpp
+++ b/engines/ags/engine/script/script.cpp
@@ -20,7 +20,6 @@
  *
  */
 
-//include <string.h>
 #include "ags/engine/script/script.h"
 #include "ags/shared/ac/common.h"
 #include "ags/engine/ac/character.h"
@@ -51,10 +50,11 @@
 #include "ags/engine/script/script_runtime.h"
 #include "ags/shared/util/string_compat.h"
 #include "ags/engine/media/audio/audio_system.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern GameSetupStruct game;
+
 extern GameState play;
 extern int gameHasBeenRestored, displayed_room;
 extern unsigned int load_new_game;
@@ -762,7 +762,7 @@ int run_interaction_commandlist(InteractionCommandList *nicl, int *timesrun, int
 			break;
 		case 20: // If Inventory Item was used
 			if (play.usedinv == IPARAM1) {
-				if (game.options[OPT_NOLOSEINV] == 0)
+				if (_GP(game).options[OPT_NOLOSEINV] == 0)
 					lose_inventory(play.usedinv);
 				if (run_interaction_commandlist(nicl->Cmds[i].Children.get(), timesrun, cmdsrun))
 					return -1;
@@ -775,7 +775,7 @@ int run_interaction_commandlist(InteractionCommandList *nicl, int *timesrun, int
 					return -1;
 			break;
 		case 22: // if a character is moving
-			if (game.chars[IPARAM1].walking)
+			if (_GP(game).chars[IPARAM1].walking)
 				if (run_interaction_commandlist(nicl->Cmds[i].Children.get(), timesrun, cmdsrun))
 					return -1;
 			break;
@@ -793,7 +793,7 @@ int run_interaction_commandlist(InteractionCommandList *nicl, int *timesrun, int
 		case 26: // Move NPC to different room
 			if (!is_valid_character(IPARAM1))
 				quit("!Move NPC to different room: invalid character specified");
-			game.chars[IPARAM1].room = IPARAM2;
+			_GP(game).chars[IPARAM1].room = IPARAM2;
 			break;
 		case 27: // Set character view
 			SetCharacterView(IPARAM1, IPARAM2);
@@ -818,12 +818,12 @@ int run_interaction_commandlist(InteractionCommandList *nicl, int *timesrun, int
 			break;
 		case 34: // Run animation
 			scAnimateCharacter(IPARAM1, IPARAM2, IPARAM3, 0);
-			GameLoopUntilValueIsZero(&game.chars[IPARAM1].animating);
+			GameLoopUntilValueIsZero(&_GP(game).chars[IPARAM1].animating);
 			break;
 		case 35: // Quick animation
 			SetCharacterView(IPARAM1, IPARAM2);
 			scAnimateCharacter(IPARAM1, IPARAM3, IPARAM4, 0);
-			GameLoopUntilValueIsZero(&game.chars[IPARAM1].animating);
+			GameLoopUntilValueIsZero(&_GP(game).chars[IPARAM1].animating);
 			ReleaseCharacterView(IPARAM1);
 			break;
 		case 36: // Set idle animation
diff --git a/engines/ags/engine/util/library_scummvm.h b/engines/ags/engine/util/library_scummvm.h
index 06e730b81e..643ce445bb 100644
--- a/engines/ags/engine/util/library_scummvm.h
+++ b/engines/ags/engine/util/library_scummvm.h
@@ -27,7 +27,6 @@
 #include "ags/shared/util/string.h"
 #include "ags/shared/debugging/out.h"
 #include "ags/plugins/plugin_base.h"
-#include "ags/engine/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/events.cpp b/engines/ags/events.cpp
index 492210eb9f..723d1edfca 100644
--- a/engines/ags/events.cpp
+++ b/engines/ags/events.cpp
@@ -22,7 +22,7 @@
 
 #include "ags/events.h"
 #include "common/system.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 extern char check_dynamic_sprites_at_exit;
diff --git a/engines/ags/game_scanner.cpp b/engines/ags/game_scanner.cpp
index c60dec4d68..998e4f085c 100644
--- a/engines/ags/game_scanner.cpp
+++ b/engines/ags/game_scanner.cpp
@@ -27,6 +27,7 @@
 #include "ags/shared/util/multifilelib.h"
 #include "ags/shared/util/string.h"
 #include "ags/engine/main/game_file.h"
+#include "ags/globals.h"
 #include "common/config-manager.h"
 #include "common/file.h"
 #include "common/hashmap.h"
@@ -40,7 +41,7 @@ namespace AGS3 {
 
 extern bool define_gamedata_location(const AGS::Shared::String &exe_path);
 extern bool engine_try_init_gamedata(AGS::Shared::String gamepak_path);
-extern GameSetupStruct game;
+
 
 void GameScanner::scan(const Common::String &startFolder) {
 	detectClashes();
@@ -142,7 +143,7 @@ void GameScanner::scanFile(const Common::String &filename) {
 		e._filename = fsNode.getName();
 		e._filename.toLowercase();
 		e._filesize = size;
-		e._gameName = game.gamename;
+		e._gameName = _GP(game).gamename;
 		e._id = convertGameNameToId(e._gameName);
 		e._md5 = md5;
 
diff --git a/engines/ags/engine/globals.cpp b/engines/ags/globals.cpp
similarity index 83%
rename from engines/ags/engine/globals.cpp
rename to engines/ags/globals.cpp
index 88b516c91a..c1c0fdc9f4 100644
--- a/engines/ags/engine/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -20,7 +20,9 @@
  *
  */
 
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
+#include "ags/shared/ac/gamesetupstruct.h"
+#include "ags/shared/ac/spritecache.h"
 
 namespace AGS3 {
 
@@ -30,10 +32,15 @@ Globals::Globals() {
 	g_globals = this;
 
 	Common::fill(&_mousecurs[0], &_mousecurs[MAXCURSORS], nullptr);
+
+	_game = new GameSetupStruct();
+	_spriteset = new SpriteCache(_game->SpriteInfos);
 }
 
 Globals::~Globals() {
 	g_globals = nullptr;
+	delete _game;
+	delete _spriteset;
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/globals.h b/engines/ags/globals.h
similarity index 95%
rename from engines/ags/engine/globals.h
rename to engines/ags/globals.h
index 73bc2e40c0..30f0d5b426 100644
--- a/engines/ags/engine/globals.h
+++ b/engines/ags/globals.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef AGS_ENGINE_GLOBALS_H
-#define AGS_ENGINE_GLOBALS_H
+#ifndef AGS_GLOBALS_H
+#define AGS_GLOBALS_H
 
 #include "ags/shared/util/string.h"
 #include "ags/shared/util/version.h"
@@ -41,6 +41,8 @@ class Bitmap;
 } // namespace AGS
 
 struct IAGSEditorDebugger;
+struct GameSetupStruct;
+class SpriteCache;
 
 class Globals {
 public:
@@ -69,6 +71,16 @@ public:
 
 	/**@}*/
 
+	/**
+	 * \defgroup game globals
+	 * @{
+	 */
+
+	GameSetupStruct *_game = nullptr;
+	SpriteCache *_spriteset;
+
+	 /**@}*/
+
 	/**
 	 * \defgroup main globals
 	 * @{
diff --git a/engines/ags/module.mk b/engines/ags/module.mk
index 4b992e1d47..fad4fd4b31 100644
--- a/engines/ags/module.mk
+++ b/engines/ags/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS = \
 	ags.o \
 	events.o \
 	game_scanner.o \
+	globals.o \
 	metaengine.o \
 	music.o \
 	lib/aastr-0.1.1/aarot.o \
@@ -93,7 +94,6 @@ MODULE_OBJS = \
 	shared/util/textstreamwriter.o \
 	shared/util/version.o \
 	shared/util/wgt2allg.o \
-	engine/globals.o \
 	engine/ac/dynobj/cc_agsdynamicobject.o \
 	engine/ac/dynobj/cc_audiochannel.o \
 	engine/ac/dynobj/cc_audioclip.o \
diff --git a/engines/ags/music.cpp b/engines/ags/music.cpp
index 1d2452361c..b999af2843 100644
--- a/engines/ags/music.cpp
+++ b/engines/ags/music.cpp
@@ -22,7 +22,7 @@
 
 #include "ags/music.h"
 #include "ags/engine/main/main.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "audio/midiparser.h"
 
 namespace AGS {
diff --git a/engines/ags/plugins/agsplugin.cpp b/engines/ags/plugins/agsplugin.cpp
index c84345092b..934d50b2e5 100644
--- a/engines/ags/plugins/agsplugin.cpp
+++ b/engines/ags/plugins/agsplugin.cpp
@@ -73,7 +73,7 @@
 #include "ags/shared/util/memory.h"
 #include "ags/shared/util/filestream.h"
 #include "ags/engine/media/audio/audio_system.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/engine/util/library.h"
 #include "ags/engine/util/library_scummvm.h"
 #include "ags/ags.h"
@@ -89,9 +89,9 @@ using namespace AGS::Engine;
 extern IGraphicsDriver *gfxDriver;
 extern int displayed_room;
 extern RoomStruct thisroom;
-extern GameSetupStruct game;
+
 extern RoomStatus *croom;
-extern SpriteCache spriteset;
+
 extern ViewStruct *views;
 extern int game_paused;
 extern GameSetup usetup;
@@ -425,10 +425,10 @@ void IAGSEngine::PollSystem() {
 
 }
 AGSCharacter *IAGSEngine::GetCharacter(int32 charnum) {
-	if (charnum >= game.numcharacters)
+	if (charnum >= _GP(game).numcharacters)
 		quit("!AGSEngine::GetCharacter: invalid character request");
 
-	return (AGSCharacter *)&game.chars[charnum];
+	return (AGSCharacter *)&_GP(game).chars[charnum];
 }
 AGSGameOptions *IAGSEngine::GetGameOptions() {
 	return (AGSGameOptions *)&play;
@@ -440,10 +440,10 @@ void IAGSEngine::SetPalette(int32 start, int32 finish, AGSColor *cpl) {
 	set_palette_range((color *)cpl, start, finish, 0);
 }
 int IAGSEngine::GetNumCharacters() {
-	return game.numcharacters;
+	return _GP(game).numcharacters;
 }
 int IAGSEngine::GetPlayerCharacter() {
-	return game.playercharacter;
+	return _GP(game).playercharacter;
 }
 void IAGSEngine::RoomToViewport(int32 *x, int32 *y) {
 	Point scrp = play.RoomToScreen(x ? data_to_game_coord(*x) : 0, y ? data_to_game_coord(*y) : 0);
@@ -484,7 +484,7 @@ void IAGSEngine::FreeBitmap(BITMAP *tofree) {
 		destroy_bitmap(tofree);
 }
 BITMAP *IAGSEngine::GetSpriteGraphic(int32 num) {
-	return (BITMAP *)spriteset[num]->GetAllegroBitmap();
+	return (BITMAP *)_GP(spriteset)[num]->GetAllegroBitmap();
 }
 BITMAP *IAGSEngine::GetRoomMask(int32 index) {
 	if (index == MASK_WALKABLE)
@@ -501,7 +501,7 @@ BITMAP *IAGSEngine::GetRoomMask(int32 index) {
 }
 AGSViewFrame *IAGSEngine::GetViewFrame(int32 view, int32 loop, int32 frame) {
 	view--;
-	if ((view < 0) || (view >= game.numviews))
+	if ((view < 0) || (view >= _GP(game).numviews))
 		quit("!IAGSEngine::GetViewFrame: invalid view");
 	if ((loop < 0) || (loop >= views[view].numLoops))
 		quit("!IAGSEngine::GetViewFrame: invalid loop");
@@ -516,7 +516,7 @@ int IAGSEngine::GetRawPixelColor(int32 color) {
 	// NOTE: it is unclear whether this has to be game colour depth or display color depth.
 	// there was no difference in the original engine, but there is now.
 	int result;
-	__my_setcolor(&result, color, game.GetColorDepth());
+	__my_setcolor(&result, color, _GP(game).GetColorDepth());
 	return result;
 }
 
@@ -539,13 +539,13 @@ int IAGSEngine::IsGamePaused() {
 	return game_paused;
 }
 int IAGSEngine::GetSpriteWidth(int32 slot) {
-	return game.SpriteInfos[slot].Width;
+	return _GP(game).SpriteInfos[slot].Width;
 }
 int IAGSEngine::GetSpriteHeight(int32 slot) {
-	return game.SpriteInfos[slot].Height;
+	return _GP(game).SpriteInfos[slot].Height;
 }
 void IAGSEngine::GetTextExtent(int32 font, const char *text, int32 *width, int32 *height) {
-	if ((font < 0) || (font >= game.numfonts)) {
+	if ((font < 0) || (font >= _GP(game).numfonts)) {
 		if (width != nullptr) width[0] = 0;
 		if (height != nullptr) height[0] = 0;
 		return;
@@ -608,10 +608,10 @@ void IAGSEngine::MarkRegionDirty(int32 left, int32 top, int32 right, int32 botto
 	plugins[this->pluginId].invalidatedRegion++;
 }
 AGSMouseCursor *IAGSEngine::GetMouseCursor(int32 cursor) {
-	if ((cursor < 0) || (cursor >= game.numcursors))
+	if ((cursor < 0) || (cursor >= _GP(game).numcursors))
 		return nullptr;
 
-	return (AGSMouseCursor *)&game.mcurs[cursor];
+	return (AGSMouseCursor *)&_GP(game).mcurs[cursor];
 }
 void IAGSEngine::GetRawColorComponents(int32 coldepth, int32 color, int32 *red, int32 *green, int32 *blue, int32 *alpha) {
 	if (red)
@@ -627,7 +627,7 @@ int IAGSEngine::MakeRawColorPixel(int32 coldepth, int32 red, int32 green, int32
 	return makeacol_depth(coldepth, red, green, blue, alpha);
 }
 int IAGSEngine::GetFontType(int32 fontNum) {
-	if ((fontNum < 0) || (fontNum >= game.numfonts))
+	if ((fontNum < 0) || (fontNum >= _GP(game).numfonts))
 		return FNT_INVALID;
 
 	if (font_supports_extended_characters(fontNum))
@@ -640,7 +640,7 @@ int IAGSEngine::CreateDynamicSprite(int32 coldepth, int32 width, int32 height) {
 	// TODO: why is this implemented right here, should not an existing
 	// script handling implementation be called instead?
 
-	int gotSlot = spriteset.GetFreeIndex();
+	int gotSlot = _GP(spriteset).GetFreeIndex();
 	if (gotSlot <= 0)
 		return 0;
 
@@ -660,7 +660,7 @@ void IAGSEngine::DeleteDynamicSprite(int32 slot) {
 	free_dynamic_sprite(slot);
 }
 int IAGSEngine::IsSpriteAlphaBlended(int32 slot) {
-	if (game.SpriteInfos[slot].Flags & SPF_ALPHACHANNEL)
+	if (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL)
 		return 1;
 	return 0;
 }
@@ -692,7 +692,7 @@ int IAGSEngine::CallGameScriptFunction(const char *name, int32 globalScript, int
 void IAGSEngine::NotifySpriteUpdated(int32 slot) {
 	int ff;
 	// wipe the character cache when we change rooms
-	for (ff = 0; ff < game.numcharacters; ff++) {
+	for (ff = 0; ff < _GP(game).numcharacters; ff++) {
 		if ((charcache[ff].inUse) && (charcache[ff].sppic == slot)) {
 			delete charcache[ff].image;
 			charcache[ff].image = nullptr;
@@ -711,10 +711,10 @@ void IAGSEngine::NotifySpriteUpdated(int32 slot) {
 
 void IAGSEngine::SetSpriteAlphaBlended(int32 slot, int32 isAlphaBlended) {
 
-	game.SpriteInfos[slot].Flags &= ~SPF_ALPHACHANNEL;
+	_GP(game).SpriteInfos[slot].Flags &= ~SPF_ALPHACHANNEL;
 
 	if (isAlphaBlended)
-		game.SpriteInfos[slot].Flags |= SPF_ALPHACHANNEL;
+		_GP(game).SpriteInfos[slot].Flags |= SPF_ALPHACHANNEL;
 }
 
 void IAGSEngine::QueueGameScriptFunction(const char *name, int32 globalScript, int32 numArgs, long arg1, long arg2) {
diff --git a/engines/ags/shared/ac/common.cpp b/engines/ags/shared/ac/common.cpp
index 147093af0e..58c5bf644f 100644
--- a/engines/ags/shared/ac/common.cpp
+++ b/engines/ags/shared/ac/common.cpp
@@ -22,7 +22,7 @@
 
 #include "ags/shared/ac/common.h"
 #include "ags/shared/util/string.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
diff --git a/engines/ags/shared/ac/gamesetupstruct.cpp b/engines/ags/shared/ac/gamesetupstruct.cpp
index b3a1bae9fb..449fd2db00 100644
--- a/engines/ags/shared/ac/gamesetupstruct.cpp
+++ b/engines/ags/shared/ac/gamesetupstruct.cpp
@@ -27,6 +27,7 @@
 #include "ags/shared/ac/dynobj/scriptaudioclip.h"
 #include "ags/shared/game/interactions.h"
 #include "ags/shared/util/alignedstream.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -97,9 +98,9 @@ ScriptAudioClip *GetAudioClipForOldStyleNumber(GameSetupStruct &game, bool is_mu
 	else
 		clip_name.Format("aSound%d", num);
 
-	for (size_t i = 0; i < game.audioClips.size(); ++i) {
-		if (clip_name.CompareNoCase(game.audioClips[i].scriptName) == 0)
-			return &game.audioClips[i];
+	for (size_t i = 0; i < _GP(game).audioClips.size(); ++i) {
+		if (clip_name.CompareNoCase(_GP(game).audioClips[i].scriptName) == 0)
+			return &_GP(game).audioClips[i];
 	}
 	return nullptr;
 }
diff --git a/engines/ags/shared/ac/mousecursor.cpp b/engines/ags/shared/ac/mousecursor.cpp
index cde072b207..c75dde9567 100644
--- a/engines/ags/shared/ac/mousecursor.cpp
+++ b/engines/ags/shared/ac/mousecursor.cpp
@@ -22,7 +22,7 @@
 
 #include "ags/shared/ac/mousecursor.h"
 #include "ags/shared/util/stream.h"
-#include "ags/engine/globals.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
diff --git a/engines/ags/shared/ac/spritecache.h b/engines/ags/shared/ac/spritecache.h
index f541a33f90..29cc9b7398 100644
--- a/engines/ags/shared/ac/spritecache.h
+++ b/engines/ags/shared/ac/spritecache.h
@@ -248,7 +248,7 @@ private:
 	void        InitNullSpriteParams(sprkey_t index);
 };
 
-extern SpriteCache spriteset;
+
 
 } // namespace AGS3
 
diff --git a/engines/ags/shared/font/fonts.cpp b/engines/ags/shared/font/fonts.cpp
index fda7bfbbf9..b45081e824 100644
--- a/engines/ags/shared/font/fonts.cpp
+++ b/engines/ags/shared/font/fonts.cpp
@@ -227,9 +227,9 @@ size_t split_lines(const char *todis, SplitLines &lines, int wii, int fonnt, siz
 	// It's hard to tell how cruicial it is for the game looks, so research may be needed.
 	// TODO: IMHO this should rely not on game format, but script API level, because it
 	// defines necessary adjustments to game scripts. If you want to fix this, find a way to
-	// pass this flag here all the way from game.options[OPT_BASESCRIPTAPI] (or game format).
+	// pass this flag here all the way from _GP(game).options[OPT_BASESCRIPTAPI] (or game format).
 	//
-	// if (game.options[OPT_BASESCRIPTAPI] < $Your current version$)
+	// if (_GP(game).options[OPT_BASESCRIPTAPI] < $Your current version$)
 	wii -= 1;
 
 	lines.Reset();
diff --git a/engines/ags/shared/game/main_game_file.cpp b/engines/ags/shared/game/main_game_file.cpp
index 2d752246df..985b5eced5 100644
--- a/engines/ags/shared/game/main_game_file.cpp
+++ b/engines/ags/shared/game/main_game_file.cpp
@@ -38,6 +38,7 @@
 #include "ags/shared/util/string_compat.h"
 #include "ags/shared/util/string_utils.h"
 #include "ags/shared/font/fonts.h"
+#include "ags/globals.h"
 #include "common/fs.h"
 
 namespace AGS3 {
@@ -77,7 +78,7 @@ String GetMainGameFileErrorText(MainGameFileErrorType err) {
 	case kMGFErr_InvalidPropertyValues:
 		return "Errors encountered when reading custom properties.";
 	case kMGFErr_NoGlobalScript:
-		return "No global script in game.";
+		return "No global script in _GP(game).";
 	case kMGFErr_CreateGlobalScriptFailed:
 		return "Failed to load global script.";
 	case kMGFErr_CreateDialogScriptFailed:
@@ -214,10 +215,10 @@ void ReadViewStruct272_Aligned(std::vector<ViewStruct272> &oldv, Stream *in, siz
 }
 
 void ReadViews(GameSetupStruct &game, ViewStruct *&views, Stream *in, GameDataVersion data_ver) {
-	int count = game.numviews;
+	int count = _GP(game).numviews;
 	views = (ViewStruct *)calloc(sizeof(ViewStruct) * count, 1);
 	if (data_ver > kGameVersion_272) { // 3.x views
-		for (int i = 0; i < game.numviews; ++i) {
+		for (int i = 0; i < _GP(game).numviews; ++i) {
 			views[i].ReadFromFile(in);
 		}
 	} else { // 2.x views
@@ -271,7 +272,7 @@ void ReadDialogs(DialogTopic *&dialog,
 	// TODO: investigate this: these strings were read much simplier in the editor, see code:
 	/*
 		char stringbuffer[1000];
-		for (bb=0;bb<thisgame.numdlgmessage;bb++) {
+		for (bb=0;bb<this_GP(game).numdlgmessage;bb++) {
 			if ((filever >= 26) && (encrypted))
 				read_string_decrypt(iii, stringbuffer);
 			else
@@ -405,16 +406,16 @@ void BuildAudioClipArray(const std::vector<String> &assets, std::vector<ScriptAu
 
 void ApplySpriteData(GameSetupStruct &game, const LoadedGameEntities &ents, GameDataVersion data_ver) {
 	// Apply sprite flags read from original format (sequential array)
-	spriteset.EnlargeTo(ents.SpriteCount - 1);
+	_GP(spriteset).EnlargeTo(ents.SpriteCount - 1);
 	for (size_t i = 0; i < ents.SpriteCount; ++i) {
-		game.SpriteInfos[i].Flags = ents.SpriteFlags[i];
+		_GP(game).SpriteInfos[i].Flags = ents.SpriteFlags[i];
 	}
 
 	// Promote sprite resolutions and mark legacy resolution setting
 	if (data_ver < kGameVersion_350) {
 		for (size_t i = 0; i < ents.SpriteCount; ++i) {
-			SpriteInfo &info = game.SpriteInfos[i];
-			if (game.IsLegacyHiRes() == info.IsLegacyHiRes())
+			SpriteInfo &info = _GP(game).SpriteInfos[i];
+			if (_GP(game).IsLegacyHiRes() == info.IsLegacyHiRes())
 				info.Flags &= ~(SPF_HIRES | SPF_VAR_RESOLUTION);
 			else
 				info.Flags |= SPF_VAR_RESOLUTION;
@@ -424,10 +425,10 @@ void ApplySpriteData(GameSetupStruct &game, const LoadedGameEntities &ents, Game
 
 void UpgradeFonts(GameSetupStruct &game, GameDataVersion data_ver) {
 	if (data_ver < kGameVersion_350) {
-		for (int i = 0; i < game.numfonts; ++i) {
-			FontInfo &finfo = game.fonts[i];
+		for (int i = 0; i < _GP(game).numfonts; ++i) {
+			FontInfo &finfo = _GP(game).fonts[i];
 			// If the game is hi-res but font is designed for low-res, then scale it up
-			if (game.IsLegacyHiRes() && game.options[OPT_HIRES_FONTS] == 0) {
+			if (_GP(game).IsLegacyHiRes() && _GP(game).options[OPT_HIRES_FONTS] == 0) {
 				finfo.SizeMultiplier = HIRES_COORD_MULTIPLIER;
 			} else {
 				finfo.SizeMultiplier = 1;
@@ -435,8 +436,8 @@ void UpgradeFonts(GameSetupStruct &game, GameDataVersion data_ver) {
 		}
 	}
 	if (data_ver < kGameVersion_351) {
-		for (size_t font = 0; font < (size_t)game.numfonts; font++) {
-			FontInfo &finfo = game.fonts[font];
+		for (size_t font = 0; font < (size_t)_GP(game).numfonts; font++) {
+			FontInfo &finfo = _GP(game).fonts[font];
 			// Thickness that corresponds to 1 game pixel
 			finfo.AutoOutlineThickness =
 				// if it's a scaled up bitmap font, move the outline out more
@@ -514,19 +515,19 @@ void UpgradeAudio(GameSetupStruct &game, GameDataVersion data_ver) {
 	BuildAudioClipArray(assets, audioclips);
 
 	// Copy gathered data over to game
-	game.audioClipTypes = audiocliptypes;
-	game.audioClips = audioclips;
+	_GP(game).audioClipTypes = audiocliptypes;
+	_GP(game).audioClips = audioclips;
 
 	// Setup sound clip played on score event
-	game.scoreClipID = -1;
+	_GP(game).scoreClipID = -1;
 }
 
 // Convert character data to the current version
 void UpgradeCharacters(GameSetupStruct &game, GameDataVersion data_ver) {
 	// TODO: this was done to simplify code transition; ideally we should be
 	// working with GameSetupStruct's getters and setters here
-	CharacterInfo *&chars = game.chars;
-	const int numcharacters = game.numcharacters;
+	CharacterInfo *&chars = _GP(game).chars;
+	const int numcharacters = _GP(game).numcharacters;
 
 	// Fixup charakter script names for 2.x (EGO -> cEgo)
 	if (data_ver <= kGameVersion_272) {
@@ -542,7 +543,7 @@ void UpgradeCharacters(GameSetupStruct &game, GameDataVersion data_ver) {
 	// Fix character walk speed for < 3.1.1
 	if (data_ver <= kGameVersion_310) {
 		for (int i = 0; i < numcharacters; i++) {
-			if (game.options[OPT_ANTIGLIDE])
+			if (_GP(game).options[OPT_ANTIGLIDE])
 				chars[i].flags |= CHF_ANTIGLIDE;
 		}
 	}
@@ -558,9 +559,9 @@ void UpgradeCharacters(GameSetupStruct &game, GameDataVersion data_ver) {
 void UpgradeMouseCursors(GameSetupStruct &game, GameDataVersion data_ver) {
 	if (data_ver <= kGameVersion_272) {
 		// Change cursor.view from 0 to -1 for non-animating cursors.
-		for (int i = 0; i < game.numcursors; ++i) {
-			if (game.mcurs[i].view == 0)
-				game.mcurs[i].view = -1;
+		for (int i = 0; i < _GP(game).numcursors; ++i) {
+			if (_GP(game).mcurs[i].view == 0)
+				_GP(game).mcurs[i].view = -1;
 		}
 	}
 }
@@ -568,13 +569,13 @@ void UpgradeMouseCursors(GameSetupStruct &game, GameDataVersion data_ver) {
 // Adjusts score clip id, depending on game data version
 void AdjustScoreSound(GameSetupStruct &game, GameDataVersion data_ver) {
 	if (data_ver < kGameVersion_320) {
-		game.scoreClipID = -1;
-		if (game.options[OPT_SCORESOUND] > 0) {
-			ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(game, false, game.options[OPT_SCORESOUND]);
+		_GP(game).scoreClipID = -1;
+		if (_GP(game).options[OPT_SCORESOUND] > 0) {
+			ScriptAudioClip *clip = GetAudioClipForOldStyleNumber(game, false, _GP(game).options[OPT_SCORESOUND]);
 			if (clip)
-				game.scoreClipID = clip->id;
+				_GP(game).scoreClipID = clip->id;
 			else
-				game.scoreClipID = -1;
+				_GP(game).scoreClipID = -1;
 		}
 	}
 }
@@ -584,8 +585,8 @@ void SetDefaultGlmsg(GameSetupStruct &game, int msgnum, const char *val) {
 	// TODO: find out why the index should be lowered by 500
 	// (or rather if we may pass correct index right away)
 	msgnum -= 500;
-	if (game.messages[msgnum] == nullptr)
-		game.messages[msgnum] = ags_strdup(val);
+	if (_GP(game).messages[msgnum] == nullptr)
+		_GP(game).messages[msgnum] = ags_strdup(val);
 }
 
 // Sets up default global messages (these are used mainly in older games)
@@ -610,19 +611,19 @@ void FixupSaveDirectory(GameSetupStruct &game) {
 #ifdef DEPRECATED
 	// If the save game folder was not specified by game author, create one of
 	// the game name, game GUID, or uniqueid, as a last resort
-	if (!game.saveGameFolderName[0]) {
-		if (game.gamename[0])
-			snprintf(game.saveGameFolderName, MAX_SG_FOLDER_LEN, "%s", game.gamename);
-		else if (game.guid[0])
-			snprintf(game.saveGameFolderName, MAX_SG_FOLDER_LEN, "%s", game.guid);
+	if (!_GP(game).saveGameFolderName[0]) {
+		if (_GP(game).gamename[0])
+			snprintf(_GP(game).saveGameFolderName, MAX_SG_FOLDER_LEN, "%s", _GP(game).gamename);
+		else if (_GP(game).guid[0])
+			snprintf(_GP(game).saveGameFolderName, MAX_SG_FOLDER_LEN, "%s", _GP(game).guid);
 		else
-			snprintf(game.saveGameFolderName, MAX_SG_FOLDER_LEN, "AGS-Game-%d", game.uniqueid);
+			snprintf(_GP(game).saveGameFolderName, MAX_SG_FOLDER_LEN, "AGS-Game-%d", _GP(game).uniqueid);
 	}
 	// Lastly, fixup folder name by removing any illegal characters
-	String s = Path::FixupSharedFilename(game.saveGameFolderName);
-	snprintf(game.saveGameFolderName, MAX_SG_FOLDER_LEN, "%s", s.GetCStr());
+	String s = Path::FixupSharedFilename(_GP(game).saveGameFolderName);
+	snprintf(_GP(game).saveGameFolderName, MAX_SG_FOLDER_LEN, "%s", s.GetCStr());
 #else
-	strcpy(game.saveGameFolderName, SAVE_FOLDER_PREFIX);
+	strcpy(_GP(game).saveGameFolderName, SAVE_FOLDER_PREFIX);
 #endif
 }
 
@@ -649,25 +650,25 @@ HGameFileError ReadGameData(LoadedGameEntities &ents, Stream *in, GameDataVersio
 
 	{
 		AlignedStream align_s(in, Shared::kAligned_Read);
-		game.GameSetupStructBase::ReadFromFile(&align_s);
+		_GP(game).GameSetupStructBase::ReadFromFile(&align_s);
 	}
 
-	if (game.GetGameRes().IsNull())
+	if (_GP(game).GetGameRes().IsNull())
 		return new MainGameFileError(kMGFErr_InvalidNativeResolution);
 
-	game.read_savegame_info(in, data_ver);
-	game.read_font_infos(in, data_ver);
+	_GP(game).read_savegame_info(in, data_ver);
+	_GP(game).read_font_infos(in, data_ver);
 	HGameFileError err = ReadSpriteFlags(ents, in, data_ver);
 	if (!err)
 		return err;
-	game.ReadInvInfo_Aligned(in);
-	err = game.read_cursors(in, data_ver);
+	_GP(game).ReadInvInfo_Aligned(in);
+	err = _GP(game).read_cursors(in, data_ver);
 	if (!err)
 		return err;
-	game.read_interaction_scripts(in, data_ver);
-	game.read_words_dictionary(in);
+	_GP(game).read_interaction_scripts(in, data_ver);
+	_GP(game).read_words_dictionary(in);
 
-	if (!game.load_compiled_script)
+	if (!_GP(game).load_compiled_script)
 		return new MainGameFileError(kMGFErr_NoGlobalScript);
 	ents.GlobalScript.reset(ccScript::CreateFromStream(in));
 	if (!ents.GlobalScript)
@@ -687,16 +688,16 @@ HGameFileError ReadGameData(LoadedGameEntities &ents, Stream *in, GameDataVersio
 		in->Seek(count * 0x204);
 	}
 
-	game.read_characters(in, data_ver);
-	game.read_lipsync(in, data_ver);
-	game.read_messages(in, data_ver);
+	_GP(game).read_characters(in, data_ver);
+	_GP(game).read_lipsync(in, data_ver);
+	_GP(game).read_messages(in, data_ver);
 
 	ReadDialogs(ents.Dialogs, ents.OldDialogScripts, ents.OldDialogSources, ents.OldSpeechLines,
-		in, data_ver, game.numdialog);
+		in, data_ver, _GP(game).numdialog);
 	HError err2 = GUI::ReadGUI(guis, in);
 	if (!err2)
 		return new MainGameFileError(kMGFErr_GameEntityFailed, err2);
-	game.numgui = guis.size();
+	_GP(game).numgui = guis.size();
 
 	if (data_ver >= kGameVersion_260) {
 		err = ReadPlugins(ents.PluginInfos, in);
@@ -704,13 +705,13 @@ HGameFileError ReadGameData(LoadedGameEntities &ents, Stream *in, GameDataVersio
 			return err;
 	}
 
-	err = game.read_customprops(in, data_ver);
+	err = _GP(game).read_customprops(in, data_ver);
 	if (!err)
 		return err;
-	err = game.read_audio(in, data_ver);
+	err = _GP(game).read_audio(in, data_ver);
 	if (!err)
 		return err;
-	game.read_room_names(in, data_ver);
+	_GP(game).read_room_names(in, data_ver);
 	return err;
 }
 
@@ -726,18 +727,18 @@ HGameFileError UpdateGameData(LoadedGameEntities &ents, GameDataVersion data_ver
 	// Global talking animation speed
 	if (data_ver < kGameVersion_312) {
 		// Fix animation speed for old formats
-		game.options[OPT_GLOBALTALKANIMSPD] = 5;
+		_GP(game).options[OPT_GLOBALTALKANIMSPD] = 5;
 	} else if (data_ver < kGameVersion_330) {
 		// Convert game option for 3.1.2 - 3.2 games
-		game.options[OPT_GLOBALTALKANIMSPD] = game.options[OPT_GLOBALTALKANIMSPD] != 0 ? 5 : (-5 - 1);
+		_GP(game).options[OPT_GLOBALTALKANIMSPD] = _GP(game).options[OPT_GLOBALTALKANIMSPD] != 0 ? 5 : (-5 - 1);
 	}
 	// Old dialog options API for pre-3.4.0.2 games
 	if (data_ver < kGameVersion_340_2) {
-		game.options[OPT_DIALOGOPTIONSAPI] = -1;
+		_GP(game).options[OPT_DIALOGOPTIONSAPI] = -1;
 	}
 	// Relative asset resolution in pre-3.5.0.8 (always enabled)
 	if (data_ver < kGameVersion_350) {
-		game.options[OPT_RELATIVEASSETRES] = 1;
+		_GP(game).options[OPT_RELATIVEASSETRES] = 1;
 	}
 	FixupSaveDirectory(game);
 	return HGameFileError::None();
diff --git a/engines/ags/shared/game/roomstruct.h b/engines/ags/shared/game/roomstruct.h
index 45fe84740a..021931f37a 100644
--- a/engines/ags/shared/game/roomstruct.h
+++ b/engines/ags/shared/game/roomstruct.h
@@ -309,7 +309,7 @@ public:
 	// Game's unique ID, corresponds to GameSetupStructBase::uniqueid.
 	// If this field has a valid value and does not match actual game's id,
 	// then engine will refuse to start this room.
-	// May be set to NO_GAME_ID_IN_ROOM_FILE to let it run within any game.
+	// May be set to NO_GAME_ID_IN_ROOM_FILE to let it run within any _GP(game).
 	int32_t                 GameID;
 	// Loaded room file's data version. This value may be used to know when
 	// the room must have behavior specific to certain version of AGS.
diff --git a/engines/ags/shared/gui/guibutton.cpp b/engines/ags/shared/gui/guibutton.cpp
index eee618201a..e599689fe2 100644
--- a/engines/ags/shared/gui/guibutton.cpp
+++ b/engines/ags/shared/gui/guibutton.cpp
@@ -25,6 +25,7 @@
 #include "ags/shared/gui/guimain.h" // TODO: extract helper functions
 #include "ags/shared/util/stream.h"
 #include "ags/shared/util/string_utils.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -263,7 +264,7 @@ void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 	// NOTE: the CLIP flag only clips the image, not the text
 	if (IsClippingImage())
 		ds->SetClip(Rect(X, Y, X + Width - 1, Y + Height - 1));
-	if (spriteset[CurrentImage] != nullptr)
+	if (_GP(spriteset)[CurrentImage] != nullptr)
 		draw_gui_sprite(ds, CurrentImage, X, Y, true);
 
 	// Draw active inventory item
@@ -279,7 +280,7 @@ void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 		}
 
 		if (place == kButtonPlace_InvItemStretch) {
-			ds->StretchBlt(spriteset[gui_inv_pic], RectWH(X + 3, Y + 3, Width - 6, Height - 6), Shared::kBitmap_Transparency);
+			ds->StretchBlt(_GP(spriteset)[gui_inv_pic], RectWH(X + 3, Y + 3, Width - 6, Height - 6), Shared::kBitmap_Transparency);
 		} else if (place == kButtonPlace_InvItemCenter) {
 			draw_gui_sprite(ds, gui_inv_pic,
 				X + Width / 2 - get_adjusted_spritewidth(gui_inv_pic) / 2,
@@ -291,8 +292,8 @@ void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 	if ((draw_disabled) && (gui_disabled_style == GUIDIS_GREYOUT)) {
 		// darken the button when disabled
 		GUI::DrawDisabledEffect(ds, RectWH(X, Y,
-			spriteset[CurrentImage]->GetWidth(),
-			spriteset[CurrentImage]->GetHeight()));
+			_GP(spriteset)[CurrentImage]->GetWidth(),
+			_GP(spriteset)[CurrentImage]->GetHeight()));
 	}
 	ds->SetClip(Rect(0, 0, ds->GetWidth() - 1, ds->GetHeight() - 1));
 
diff --git a/engines/ags/shared/gui/guilistbox.cpp b/engines/ags/shared/gui/guilistbox.cpp
index f908df0dac..91a07e07fd 100644
--- a/engines/ags/shared/gui/guilistbox.cpp
+++ b/engines/ags/shared/gui/guilistbox.cpp
@@ -362,7 +362,7 @@ void GUIListBox::ReadFromSavegame(Stream *in, GuiSvgVersion svg_ver) {
 		Items[i] = StrUtil::ReadString(in);
 	// TODO: investigate this, it might be unreasonable to save and read
 	// savegame index like that because list of savegames may easily change
-	// in between writing and restoring the game. Perhaps clearing and forcing
+	// in between writing and restoring the _GP(game). Perhaps clearing and forcing


Commit: 2ecc1dcd41d6900720e7be5db50b3535e87f77b6
    https://github.com/scummvm/scummvm/commit/2ecc1dcd41d6900720e7be5db50b3535e87f77b6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-02-26T21:30:39-08:00

Commit Message:
AGS: Change some Strings to const char *

Changed paths:
    engines/ags/shared/game/main_game_file.cpp
    engines/ags/shared/game/main_game_file.h


diff --git a/engines/ags/shared/game/main_game_file.cpp b/engines/ags/shared/game/main_game_file.cpp
index 985b5eced5..d59a74672d 100644
--- a/engines/ags/shared/game/main_game_file.cpp
+++ b/engines/ags/shared/game/main_game_file.cpp
@@ -45,9 +45,9 @@ namespace AGS3 {
 namespace AGS {
 namespace Shared {
 
-const String MainGameSource::DefaultFilename_v3 = "game28.dta";
-const String MainGameSource::DefaultFilename_v2 = "ac2game.dta";
-const String MainGameSource::Signature = "Adventure Creator Game File v2";
+const char *MainGameSource::DefaultFilename_v3 = "game28.dta";
+const char *MainGameSource::DefaultFilename_v2 = "ac2game.dta";
+const char *MainGameSource::Signature = "Adventure Creator Game File v2";
 
 MainGameSource::MainGameSource()
 	: DataVersion(kGameVersion_Undefined) {
@@ -124,7 +124,7 @@ bool IsMainGameLibrary(const String &filename) {
 // Begins reading main game file from a generic stream
 HGameFileError OpenMainGameFileBase(PStream &in, MainGameSource &src) {
 	// Check data signature
-	String data_sig = String::FromStreamCount(in.get(), MainGameSource::Signature.GetLength());
+	String data_sig = String::FromStreamCount(in.get(), strlen(MainGameSource::Signature));
 	if (data_sig.Compare(MainGameSource::Signature))
 		return new MainGameFileError(kMGFErr_SignatureFailed);
 	// Read data format version and requested engine version
diff --git a/engines/ags/shared/game/main_game_file.h b/engines/ags/shared/game/main_game_file.h
index 108abf51b1..8722add15b 100644
--- a/engines/ags/shared/game/main_game_file.h
+++ b/engines/ags/shared/game/main_game_file.h
@@ -83,10 +83,10 @@ typedef std::shared_ptr<Stream> PStream;
 // MainGameSource defines a successfully opened main game file
 struct MainGameSource {
 	// Standart main game file names for 3.* and 2.* games respectively
-	static const String DefaultFilename_v3;
-	static const String DefaultFilename_v2;
+	static const char *DefaultFilename_v3;
+	static const char *DefaultFilename_v2;
 	// Signature of the current game format
-	static const String Signature;
+	static const char *Signature;
 
 	// Name of the asset file
 	String              Filename;




More information about the Scummvm-git-logs mailing list