[Scummvm-git-logs] scummvm master -> 37b563ef35587dacd772016e2e32584614be92e0

dreammaster dreammaster at scummvm.org
Mon Mar 8 03:23:50 UTC 2021


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

Summary:
3fb4b083ec AGS: Move audio globals to Globals
26a69e12f7 AGS: Move button.cpp globals to Globals
37b563ef35 AGS: Move game globals to Globals


Commit: 3fb4b083eca26b8000abd0b4df81fe2af9ca81db
    https://github.com/scummvm/scummvm/commit/3fb4b083eca26b8000abd0b4df81fe2af9ca81db
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-03-07T15:54:11-08:00

Commit Message:
AGS: Move audio globals to Globals

Changed paths:
    engines/ags/engine/ac/audioclip.cpp
    engines/ags/engine/ac/dynobj/cc_audiochannel.cpp
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/ac/global_audio.cpp
    engines/ags/engine/ac/system.cpp
    engines/ags/engine/game/game_init.cpp
    engines/ags/engine/game/savegame.cpp
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/engine/media/audio/audio.cpp
    engines/ags/engine/media/audio/audio.h
    engines/ags/globals.cpp
    engines/ags/globals.h


diff --git a/engines/ags/engine/ac/audioclip.cpp b/engines/ags/engine/ac/audioclip.cpp
index 85ecff1395..1706b16a79 100644
--- a/engines/ags/engine/ac/audioclip.cpp
+++ b/engines/ags/engine/ac/audioclip.cpp
@@ -32,8 +32,6 @@
 
 namespace AGS3 {
 
-extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
-
 int AudioClip_GetID(ScriptAudioClip *clip) {
 	return clip->id;
 }
@@ -54,7 +52,7 @@ void AudioClip_Stop(ScriptAudioClip *clip) {
 	for (int i = 0; i < MAX_SOUND_CHANNELS; i++) {
 		auto *ch = lock.GetChannelIfPlaying(i);
 		if ((ch != nullptr) && (ch->_sourceClip == clip)) {
-			AudioChannel_Stop(&scrAudioChannel[i]);
+			AudioChannel_Stop(&_G(scrAudioChannel)[i]);
 		}
 	}
 }
diff --git a/engines/ags/engine/ac/dynobj/cc_audiochannel.cpp b/engines/ags/engine/ac/dynobj/cc_audiochannel.cpp
index 1edc98acab..c4faca4cd2 100644
--- a/engines/ags/engine/ac/dynobj/cc_audiochannel.cpp
+++ b/engines/ags/engine/ac/dynobj/cc_audiochannel.cpp
@@ -23,11 +23,10 @@
 #include "ags/engine/ac/dynobj/cc_audiochannel.h"
 #include "ags/engine/ac/dynobj/scriptaudiochannel.h"
 #include "ags/engine/media/audio/audio_system.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
-
 const char *CCAudioChannel::GetType() {
 	return "AudioChannel";
 }
@@ -42,7 +41,7 @@ int CCAudioChannel::Serialize(const char *address, char *buffer, int bufsize) {
 void CCAudioChannel::Unserialize(int index, const char *serializedData, int dataSize) {
 	StartUnserialize(serializedData, dataSize);
 	int id = UnserializeInt();
-	ccRegisterUnserializedObject(index, &scrAudioChannel[id], this);
+	ccRegisterUnserializedObject(index, &_G(scrAudioChannel)[id], this);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index f4c2995561..ea0c633f4f 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -109,7 +109,6 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
 extern int cur_mode, cur_cursor;
 extern SpeechLipSyncLine *splipsync;
 extern int numLipLines, curLipLine, curLipLinePhoneme;
@@ -188,7 +187,7 @@ void Game_StopAudio(int audioType) {
 		if (audioType == SCR_NO_VALUE) {
 			stop_or_fade_out_channel(aa);
 		} else {
-			ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&scrAudioChannel[aa]);
+			ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&_G(scrAudioChannel)[aa]);
 			if ((clip != nullptr) && (clip->type == audioType))
 				stop_or_fade_out_channel(aa);
 		}
@@ -205,7 +204,7 @@ int Game_IsAudioPlaying(int audioType) {
 		return 0;
 
 	for (int aa = 0; aa < MAX_SOUND_CHANNELS; aa++) {
-		ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&scrAudioChannel[aa]);
+		ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&_G(scrAudioChannel)[aa]);
 		if (clip != nullptr) {
 			if ((clip->type == audioType) || (audioType == SCR_NO_VALUE)) {
 				return 1;
@@ -235,7 +234,7 @@ void Game_SetAudioTypeVolume(int audioType, int volume, int changeType) {
 	        (changeType == VOL_BOTH)) {
 		AudioChannelsLock lock;
 		for (int aa = 0; aa < MAX_SOUND_CHANNELS; aa++) {
-			ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&scrAudioChannel[aa]);
+			ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&_G(scrAudioChannel)[aa]);
 			if ((clip != nullptr) && (clip->type == audioType)) {
 				auto *ch = lock.GetChannel(aa);
 				if (ch)
@@ -255,7 +254,7 @@ void Game_SetAudioTypeVolume(int audioType, int volume, int changeType) {
 }
 
 int Game_GetMODPattern() {
-	if (current_music_type != MUS_MOD)
+	if (_G(current_music_type) != MUS_MOD)
 		return -1;
 	AudioChannelsLock lock;
 	auto *music_ch = lock.GetChannelIfPlaying(SCHAN_MUSIC);
@@ -1360,10 +1359,10 @@ HSaveError restore_game_audioclips_and_crossfade(Stream *in, RestoredData &r_dat
 				chan_info.Speed = in->ReadInt32();
 		}
 	}
-	crossFading = in->ReadInt32();
-	crossFadeVolumePerStep = in->ReadInt32();
-	crossFadeStep = in->ReadInt32();
-	crossFadeVolumeAtStart = in->ReadInt32();
+	_G(crossFading) = in->ReadInt32();
+	_G(crossFadeVolumePerStep) = in->ReadInt32();
+	_G(crossFadeStep) = in->ReadInt32();
+	_G(crossFadeVolumeAtStart) = in->ReadInt32();
 	return HSaveError::None();
 }
 
@@ -1474,7 +1473,7 @@ HSaveError restore_game_data(Stream *in, SavegameVersion svg_version, const Pres
 	}
 
 	// preserve legacy music type setting
-	current_music_type = in->ReadInt32();
+	_G(current_music_type) = in->ReadInt32();
 
 	return HSaveError::None();
 }
diff --git a/engines/ags/engine/ac/global_audio.cpp b/engines/ags/engine/ac/global_audio.cpp
index 576e133984..5c48f5a74c 100644
--- a/engines/ags/engine/ac/global_audio.cpp
+++ b/engines/ags/engine/ac/global_audio.cpp
@@ -178,7 +178,7 @@ void PlayMusicResetQueue(int newmus) {
 }
 
 void SeekMIDIPosition(int position) {
-	if (_GP(play).silent_midi == 0 && current_music_type != MUS_MIDI)
+	if (_GP(play).silent_midi == 0 && _G(current_music_type) != MUS_MIDI)
 		return;
 
 	AudioChannelsLock lock;
@@ -190,7 +190,7 @@ void SeekMIDIPosition(int position) {
 int GetMIDIPosition() {
 	if (_GP(play).fast_forward)
 		return 99999;
-	if (_GP(play).silent_midi == 0 && current_music_type != MUS_MIDI)
+	if (_GP(play).silent_midi == 0 && _G(current_music_type) != MUS_MIDI)
 		return -1; // returns -1 on failure according to old manuals
 
 	AudioChannelsLock lock;
@@ -208,18 +208,18 @@ int IsMusicPlaying() {
 		return 0;
 
 	// This only returns positive if there was a music started by old audio API
-	if (current_music_type == 0)
+	if (_G(current_music_type) == 0)
 		return 0;
 
 	AudioChannelsLock lock;
 	auto *ch = lock.GetChannel(SCHAN_MUSIC);
 	if (ch == nullptr) {
 		// This was probably a hacky fix in case it was not reset by game update; TODO: find out if needed
-		current_music_type = 0;
+		_G(current_music_type) = 0;
 		return 0;
 	}
 
-	bool result = (ch->is_playing()) || (crossFading > 0 && (lock.GetChannelIfPlaying(crossFading) != nullptr));
+	bool result = (ch->is_playing()) || (_G(crossFading) > 0 && (lock.GetChannelIfPlaying(_G(crossFading)) != nullptr));
 	return result ? 1 : 0;
 }
 
@@ -259,7 +259,7 @@ int PlayMusicQueued(int musnum) {
 
 		clear_music_cache();
 
-		cachedQueuedMusic = load_music_from_disk(musnum, (_GP(play).music_repeat > 0));
+		_G(cachedQueuedMusic) = load_music_from_disk(musnum, (_GP(play).music_repeat > 0));
 	}
 
 	return _GP(play).music_queue_size;
@@ -271,7 +271,7 @@ void scr_StopMusic() {
 }
 
 void SeekMODPattern(int patnum) {
-	if (current_music_type != MUS_MOD)
+	if (_G(current_music_type) != MUS_MOD)
 		return;
 
 	AudioChannelsLock lock;
@@ -283,12 +283,12 @@ void SeekMODPattern(int patnum) {
 }
 
 void SeekMP3PosMillis(int posn) {
-	if (current_music_type != MUS_MP3 && current_music_type != MUS_OGG)
+	if (_G(current_music_type) != MUS_MP3 && _G(current_music_type) != MUS_OGG)
 		return;
 
 	AudioChannelsLock lock;
 	auto *mus_ch = lock.GetChannel(SCHAN_MUSIC);
-	auto *cf_ch = (crossFading > 0) ? lock.GetChannel(crossFading) : nullptr;
+	auto *cf_ch = (_G(crossFading) > 0) ? lock.GetChannel(_G(crossFading)) : nullptr;
 	if (cf_ch)
 		cf_ch->seek(posn);
 	else if (mus_ch)
@@ -299,7 +299,7 @@ int GetMP3PosMillis() {
 	// in case they have "while (GetMP3PosMillis() < 5000) "
 	if (_GP(play).fast_forward)
 		return 999999;
-	if (current_music_type != MUS_MP3 && current_music_type != MUS_OGG)
+	if (_G(current_music_type) != MUS_MP3 && _G(current_music_type) != MUS_OGG)
 		return 0;  // returns 0 on failure according to old manuals
 
 	AudioChannelsLock lock;
@@ -394,7 +394,7 @@ void PlayMP3File(const char *filename) {
 		if (clip) {
 			if (clip->play()) {
 				set_clip_to_channel(useChan, clip);
-				current_music_type = MUS_OGG;
+				_G(current_music_type) = MUS_OGG;
 				_GP(play).cur_music_number = 1000;
 				// save the filename (if it's not what we were supplied with)
 				if (filename != &_GP(play).playmp3file_name[0])
@@ -412,7 +412,7 @@ void PlayMP3File(const char *filename) {
 		if (clip) {
 			if (clip->play()) {
 				set_clip_to_channel(useChan, clip);
-				current_music_type = MUS_MP3;
+				_G(current_music_type) = MUS_MP3;
 				_GP(play).cur_music_number = 1000;
 				// save the filename (if it's not what we were supplied with)
 				if (filename != &_GP(play).playmp3file_name[0])
@@ -436,7 +436,7 @@ void PlayMP3File(const char *filename) {
 }
 
 void PlaySilentMIDI(int mnum) {
-	if (current_music_type == MUS_MIDI)
+	if (_G(current_music_type) == MUS_MIDI)
 		quit("!PlaySilentMIDI: proper midi music is in progress");
 
 	_GP(play).silent_midi = mnum;
@@ -501,12 +501,10 @@ int IsMusicVoxAvailable() {
 	return _GP(play).separate_music_lib;
 }
 
-extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
-
 ScriptAudioChannel *PlayVoiceClip(CharacterInfo *ch, int sndid, bool as_speech) {
 	if (!play_voice_nonblocking(ch->index_id, sndid, as_speech))
 		return NULL;
-	return &scrAudioChannel[SCHAN_SPEECH];
+	return &_G(scrAudioChannel)[SCHAN_SPEECH];
 }
 
 // Construct an asset name for the voice-over clip for the given character and cue id
diff --git a/engines/ags/engine/ac/system.cpp b/engines/ags/engine/ac/system.cpp
index f7d2950b03..c3770e21ce 100644
--- a/engines/ags/engine/ac/system.cpp
+++ b/engines/ags/engine/ac/system.cpp
@@ -52,7 +52,6 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
 extern IGraphicsDriver *gfxDriver;
 extern volatile bool switched_away;
 
@@ -176,7 +175,7 @@ ScriptAudioChannel *System_GetAudioChannels(int index) {
 	if ((index < 0) || (index >= MAX_SOUND_CHANNELS))
 		quit("!System.AudioChannels: invalid sound channel index");
 
-	return &scrAudioChannel[index];
+	return &_G(scrAudioChannel)[index];
 }
 
 int System_GetVolume() {
diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index 69337d950f..e6df98a9c0 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -63,7 +63,6 @@ extern IDriverDependantBitmap **actspsbmp;
 extern Bitmap **actspswb;
 extern IDriverDependantBitmap **actspswbbmp;
 extern CachedActSpsData *actspswbcache;
-extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
 extern ScriptDialogOptionsRendering ccDialogOptionsRendering;
 extern ScriptDrawingSurface *dialogOptionsRenderingSurface;
 extern AGSStaticObject GlobalStaticManager;
@@ -94,8 +93,8 @@ String GetGameInitErrorText(GameInitErrorType err) {
 // Initializes audio channels and clips and registers them in the script system
 void InitAndRegisterAudioObjects() {
 	for (int i = 0; i <= MAX_SOUND_CHANNELS; ++i) {
-		scrAudioChannel[i].id = i;
-		ccRegisterManagedObject(&scrAudioChannel[i], &_GP(ccDynamicAudio));
+		_G(scrAudioChannel)[i].id = i;
+		ccRegisterManagedObject(&_G(scrAudioChannel)[i], &_GP(ccDynamicAudio));
 	}
 
 	for (size_t i = 0; i < _GP(game).audioClips.size(); ++i) {
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 6cfd918def..98d2d1c213 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -626,17 +626,17 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 		first_room_initialization();
 	}
 
-	if ((_GP(play).music_queue_size > 0) && (cachedQueuedMusic == nullptr)) {
-		cachedQueuedMusic = load_music_from_disk(_GP(play).music_queue[0], 0);
+	if ((_GP(play).music_queue_size > 0) && (_G(cachedQueuedMusic) == nullptr)) {
+		_G(cachedQueuedMusic) = load_music_from_disk(_GP(play).music_queue[0], 0);
 	}
 
 	// Test if the old-style audio had playing music and it was properly loaded
-	if (current_music_type > 0) {
+	if (_G(current_music_type) > 0) {
 		AudioChannelsLock lock;
 
-		if ((crossFading > 0 && !lock.GetChannelIfPlaying(crossFading)) ||
-			(crossFading <= 0 && !lock.GetChannelIfPlaying(SCHAN_MUSIC))) {
-			current_music_type = 0; // playback failed, reset flag
+		if ((_G(crossFading) > 0 && !lock.GetChannelIfPlaying(_G(crossFading))) ||
+			(_G(crossFading) <= 0 && !lock.GetChannelIfPlaying(SCHAN_MUSIC))) {
+			_G(current_music_type) = 0; // playback failed, reset flag
 		}
 	}
 
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 0dae07d1ce..d45e138c59 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -374,12 +374,12 @@ HSaveError WriteAudio(PStream out) {
 		}
 	}
 
-	out->WriteInt32(crossFading);
-	out->WriteInt32(crossFadeVolumePerStep);
-	out->WriteInt32(crossFadeStep);
-	out->WriteInt32(crossFadeVolumeAtStart);
+	out->WriteInt32(_G(crossFading));
+	out->WriteInt32(_G(crossFadeVolumePerStep));
+	out->WriteInt32(_G(crossFadeStep));
+	out->WriteInt32(_G(crossFadeVolumeAtStart));
 	// CHECKME: why this needs to be saved?
-	out->WriteInt32(current_music_type);
+	out->WriteInt32(_G(current_music_type));
 
 	// Ambient sound
 	for (int i = 0; i < MAX_SOUND_CHANNELS; ++i)
@@ -427,12 +427,12 @@ HSaveError ReadAudio(PStream in, int32_t cmp_ver, const PreservedParams &pp, Res
 		}
 	}
 
-	crossFading = in->ReadInt32();
-	crossFadeVolumePerStep = in->ReadInt32();
-	crossFadeStep = in->ReadInt32();
-	crossFadeVolumeAtStart = in->ReadInt32();
+	_G(crossFading) = in->ReadInt32();
+	_G(crossFadeVolumePerStep) = in->ReadInt32();
+	_G(crossFadeStep) = in->ReadInt32();
+	_G(crossFadeVolumeAtStart) = in->ReadInt32();
 	// preserve legacy music type setting
-	current_music_type = in->ReadInt32();
+	_G(current_music_type) = in->ReadInt32();
 
 	// Ambient sound
 	for (int i = 0; i < MAX_SOUND_CHANNELS; ++i)
diff --git a/engines/ags/engine/media/audio/audio.cpp b/engines/ags/engine/media/audio/audio.cpp
index 62d90ed8d9..b847f01d5d 100644
--- a/engines/ags/engine/media/audio/audio.cpp
+++ b/engines/ags/engine/media/audio/audio.cpp
@@ -100,22 +100,16 @@ void set_clip_to_channel(int chanid, SOUNDCLIP *clip) {
 }
 //-----------------------
 
-volatile bool _audio_doing_crossfade;
-
 extern CharacterInfo *playerchar;
 
 extern volatile int switching_away_from_game;
 
-ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
-char acaudio_buffer[256];
-int reserved_channel_count = 0;
-
 void calculate_reserved_channel_count() {
 	int reservedChannels = 0;
 	for (size_t i = 0; i < _GP(game).audioClipTypes.size(); i++) {
 		reservedChannels += _GP(game).audioClipTypes[i].reservedChannels;
 	}
-	reserved_channel_count = reservedChannels;
+	_G(reserved_channel_count) = reservedChannels;
 }
 
 void update_clip_default_volume(ScriptAudioClip *audioClip) {
@@ -153,7 +147,7 @@ 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]);
+	ScriptAudioClip *sourceClip = AudioChannel_GetPlayingClip(&_G(scrAudioChannel)[fadeOutChannel]);
 	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 {
@@ -171,7 +165,7 @@ static int find_free_audio_channel(ScriptAudioClip *clip, int priority, bool int
 	if (!interruptEqualPriority)
 		priority--;
 
-	int startAtChannel = reserved_channel_count;
+	int startAtChannel = _G(reserved_channel_count);
 	int endBeforeChannel = MAX_SOUND_CHANNELS;
 
 	if (_GP(game).audioClipTypes[clip->type].reservedChannels > 0) {
@@ -261,7 +255,7 @@ static void audio_update_polled_stuff() {
 		SOUNDCLIP *ch = lock.GetChannel(_GP(play).crossfading_out_channel);
 		int newVolume = ch ? ch->get_volume() - _GP(play).crossfade_out_volume_per_step : 0;
 		if (newVolume > 0) {
-			AudioChannel_SetVolume(&scrAudioChannel[_GP(play).crossfading_out_channel], newVolume);
+			AudioChannel_SetVolume(&_G(scrAudioChannel)[_GP(play).crossfading_out_channel], newVolume);
 		} else {
 			stop_and_destroy_channel(_GP(play).crossfading_out_channel);
 			_GP(play).crossfading_out_channel = 0;
@@ -278,7 +272,7 @@ static void audio_update_polled_stuff() {
 			newVolume = _GP(play).crossfade_final_volume_in;
 		}
 
-		AudioChannel_SetVolume(&scrAudioChannel[_GP(play).crossfading_in_channel], newVolume);
+		AudioChannel_SetVolume(&_G(scrAudioChannel)[_GP(play).crossfading_in_channel], newVolume);
 
 		if (newVolume >= _GP(play).crossfade_final_volume_in) {
 			_GP(play).crossfading_in_channel = 0;
@@ -388,7 +382,7 @@ ScriptAudioChannel *play_audio_clip_on_channel(int channel, ScriptAudioClip *cli
 		apply_volume_drop_to_clip(soundfx);
 
 	set_clip_to_channel(channel, soundfx);
-	return &scrAudioChannel[channel];
+	return &_G(scrAudioChannel)[channel];
 }
 
 void remove_clips_of_type_from_queue(int audioType) {
@@ -463,7 +457,7 @@ void stop_and_destroy_channel_ex(int chid, bool resetLegacyMusicSettings) {
 		_GP(play).crossfading_in_channel = 0;
 	if (_GP(play).crossfading_out_channel == chid)
 		_GP(play).crossfading_out_channel = 0;
-	// don't update 'crossFading' here as it is updated in all the cross-fading functions.
+	// don't update '_G(crossFading)' here as it is updated in all the cross-fading functions.
 
 	// destroyed an ambient sound channel
 	if (_GP(ambient)[chid].channel > 0)
@@ -471,7 +465,7 @@ void stop_and_destroy_channel_ex(int chid, bool resetLegacyMusicSettings) {
 
 	if ((chid == SCHAN_MUSIC) && (resetLegacyMusicSettings)) {
 		_GP(play).cur_music_number = -1;
-		current_music_type = 0;
+		_G(current_music_type) = 0;
 	}
 }
 
@@ -617,7 +611,7 @@ void stop_all_sound_and_music() {
 	stopmusic();
 	stop_voice_nonblocking();
 	// make sure it doesn't start crossfading when it comes back
-	crossFading = 0;
+	_G(crossFading) = 0;
 	// any ambient sound will be aborted
 	for (int i = 0; i <= MAX_SOUND_CHANNELS; i++)
 		stop_and_destroy_channel(i);
@@ -684,46 +678,29 @@ int play_sound(int val1) {
 	return play_sound_priority(val1, 10);
 }
 
-
-//=============================================================================
-
-
-// This is an indicator of a music played by an old audio system
-// (to distinguish from the new system API)
-int current_music_type = 0;
-// crossFading is >0 (channel number of new track), or -1 (old
-// track fading out, no new track)
-int crossFading = 0, crossFadeVolumePerStep = 0, crossFadeStep = 0;
-int crossFadeVolumeAtStart = 0;
-SOUNDCLIP *cachedQueuedMusic = nullptr;
-
 //=============================================================================
-// Music update is scheduled when the voice speech stops;
-// we do a small delay before reverting any volume adjustments
-static bool music_update_scheduled = false;
-static uint32 music_update_at = 0; // AGS_Clock::now();
 
 void cancel_scheduled_music_update() {
-	music_update_scheduled = false;
+	_G(music_update_scheduled) = false;
 }
 
 void schedule_music_update_at(AGS_Clock::time_point at) {
-	music_update_scheduled = true;
-	music_update_at = at;
+	_G(music_update_scheduled) = true;
+	_G(music_update_at) = at;
 }
 
 void postpone_scheduled_music_update_by(std::chrono::milliseconds duration) {
-	if (!music_update_scheduled) {
+	if (!_G(music_update_scheduled)) {
 		return;
 	}
-	music_update_at += duration;
+	_G(music_update_at) += duration;
 }
 
 void process_scheduled_music_update() {
-	if (!music_update_scheduled) {
+	if (!_G(music_update_scheduled)) {
 		return;
 	}
-	if (music_update_at > AGS_Clock::now()) {
+	if (_G(music_update_at) > AGS_Clock::now()) {
 		return;
 	}
 	cancel_scheduled_music_update();
@@ -736,10 +713,10 @@ void process_scheduled_music_update() {
 
 void clear_music_cache() {
 
-	if (cachedQueuedMusic != nullptr) {
-		cachedQueuedMusic->destroy();
-		delete cachedQueuedMusic;
-		cachedQueuedMusic = nullptr;
+	if (_G(cachedQueuedMusic) != nullptr) {
+		_G(cachedQueuedMusic)->destroy();
+		delete _G(cachedQueuedMusic);
+		_G(cachedQueuedMusic) = nullptr;
 	}
 
 }
@@ -755,26 +732,26 @@ void play_next_queued() {
 		if (tuneToPlay >= QUEUED_MUSIC_REPEAT) {
 			// Loop it!
 			_GP(play).music_repeat++;
-			play_new_music(tuneToPlay - QUEUED_MUSIC_REPEAT, cachedQueuedMusic);
+			play_new_music(tuneToPlay - QUEUED_MUSIC_REPEAT, _G(cachedQueuedMusic));
 			_GP(play).music_repeat--;
 		} else {
 			// Don't loop it!
 			int repeatWas = _GP(play).music_repeat;
 			_GP(play).music_repeat = 0;
-			play_new_music(tuneToPlay, cachedQueuedMusic);
+			play_new_music(tuneToPlay, _G(cachedQueuedMusic));
 			_GP(play).music_repeat = repeatWas;
 		}
 
 		// don't free the memory, as it has been transferred onto the
 		// main music channel
-		cachedQueuedMusic = nullptr;
+		_G(cachedQueuedMusic) = nullptr;
 
 		_GP(play).music_queue_size--;
 		for (int i = 0; i < _GP(play).music_queue_size; i++)
 			_GP(play).music_queue[i] = _GP(play).music_queue[i + 1];
 
 		if (_GP(play).music_queue_size > 0)
-			cachedQueuedMusic = load_music_from_disk(_GP(play).music_queue[0], 0);
+			_G(cachedQueuedMusic) = load_music_from_disk(_GP(play).music_queue[0], 0);
 	}
 
 }
@@ -820,12 +797,12 @@ void update_audio_system_on_game_loop() {
 
 	process_scheduled_music_update();
 
-	_audio_doing_crossfade = true;
+	_G(audio_doing_crossfade) = true;
 
 	audio_update_polled_stuff();
 
-	if (crossFading) {
-		crossFadeStep++;
+	if (_G(crossFading)) {
+		_G(crossFadeStep)++;
 		update_music_volume();
 	}
 
@@ -836,7 +813,7 @@ void update_audio_system_on_game_loop() {
 			_GP(play).cur_music_number = -1;
 			play_next_queued();
 		} else if ((_GP(game).options[OPT_CROSSFADEMUSIC] > 0) &&
-			(_GP(play).music_queue_size > 0) && (!crossFading)) {
+			(_GP(play).music_queue_size > 0) && (!_G(crossFading))) {
 			// want to crossfade, and new tune in the queue
 			auto *ch = lock.GetChannel(SCHAN_MUSIC);
 			if (ch) {
@@ -854,75 +831,75 @@ void update_audio_system_on_game_loop() {
 		}
 	}
 
-	_audio_doing_crossfade = false;
+	_G(audio_doing_crossfade) = false;
 
 }
 
 void stopmusic() {
 	AudioChannelsLock lock;
 
-	if (crossFading > 0) {
+	if (_G(crossFading) > 0) {
 		// stop in the middle of a new track fading in
 		// Abort the new track, and let the old one finish fading out
-		stop_and_destroy_channel(crossFading);
-		crossFading = -1;
-	} else if (crossFading < 0) {
+		stop_and_destroy_channel(_G(crossFading));
+		_G(crossFading) = -1;
+	} else if (_G(crossFading) < 0) {
 		// the music is already fading out
 		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;
+			_G(crossFading) = 0;
+			_G(crossFadeStep) = 0;
 			update_music_volume();
 		}
 	} else if ((_GP(game).options[OPT_CROSSFADEMUSIC] > 0)
 		&& (lock.GetChannelIfPlaying(SCHAN_MUSIC) != nullptr)
-		&& (current_music_type != 0)
-		&& (current_music_type != MUS_MIDI)
-		&& (current_music_type != MUS_MOD)) {
-
-		crossFading = -1;
-		crossFadeStep = 0;
-		crossFadeVolumePerStep = _GP(game).options[OPT_CROSSFADEMUSIC];
-		crossFadeVolumeAtStart = calculate_max_volume();
+		&& (_G(current_music_type) != 0)
+		&& (_G(current_music_type) != MUS_MIDI)
+		&& (_G(current_music_type) != MUS_MOD)) {
+
+		_G(crossFading) = -1;
+		_G(crossFadeStep) = 0;
+		_G(crossFadeVolumePerStep) = _GP(game).options[OPT_CROSSFADEMUSIC];
+		_G(crossFadeVolumeAtStart) = calculate_max_volume();
 	} else
 		stop_and_destroy_channel(SCHAN_MUSIC);
 
 	_GP(play).cur_music_number = -1;
-	current_music_type = 0;
+	_G(current_music_type) = 0;
 }
 
 void update_music_volume() {
 	AudioChannelsLock lock;
 
-	if ((current_music_type) || (crossFading < 0)) {
+	if ((_G(current_music_type)) || (_G(crossFading) < 0)) {
 		// targetVol is the maximum volume we're fading in to
 		// newvol is the starting volume that we faded out from
 		int targetVol = calculate_max_volume();
 		int newvol;
-		if (crossFading)
-			newvol = crossFadeVolumeAtStart;
+		if (_G(crossFading))
+			newvol = _G(crossFadeVolumeAtStart);
 		else
 			newvol = targetVol;
 
 		// fading out old track, target volume is silence
-		if (crossFading < 0)
+		if (_G(crossFading) < 0)
 			targetVol = 0;
 
-		if (crossFading) {
-			int curvol = crossFadeVolumePerStep * crossFadeStep;
+		if (_G(crossFading)) {
+			int curvol = _G(crossFadeVolumePerStep) * _G(crossFadeStep);
 
 			if ((curvol > targetVol) && (curvol > newvol)) {
 				// it has fully faded to the new track
 				newvol = targetVol;
 				stop_and_destroy_channel_ex(SCHAN_MUSIC, false);
-				if (crossFading > 0) {
-					lock.MoveChannel(SCHAN_MUSIC, crossFading);
+				if (_G(crossFading) > 0) {
+					lock.MoveChannel(SCHAN_MUSIC, _G(crossFading));
 				}
-				crossFading = 0;
+				_G(crossFading) = 0;
 			} else {
-				if (crossFading > 0) {
-					auto *ch = lock.GetChannel(crossFading);
+				if (_G(crossFading) > 0) {
+					auto *ch = lock.GetChannel(_G(crossFading));
 					if (ch)
 						ch->set_volume((curvol > targetVol) ? targetVol : curvol);
 				}
@@ -942,11 +919,11 @@ void update_music_volume() {
 // new music
 void post_new_music_check(int newchannel) {
 	AudioChannelsLock lock;
-	if ((crossFading > 0) && (lock.GetChannel(crossFading) == nullptr)) {
-		crossFading = 0;
+	if ((_G(crossFading) > 0) && (lock.GetChannel(_G(crossFading)) == nullptr)) {
+		_G(crossFading) = 0;
 		// Was fading out but then they played invalid music, continue to fade out
 		if (lock.GetChannel(SCHAN_MUSIC) != nullptr)
-			crossFading = -1;
+			_G(crossFading) = -1;
 	}
 
 }
@@ -958,32 +935,32 @@ int prepare_for_new_music() {
 
 	if ((_GP(game).options[OPT_CROSSFADEMUSIC] > 0)
 		&& (lock.GetChannelIfPlaying(SCHAN_MUSIC) != nullptr)
-		&& (current_music_type != MUS_MIDI)
-		&& (current_music_type != MUS_MOD)) {
+		&& (_G(current_music_type) != MUS_MIDI)
+		&& (_G(current_music_type) != MUS_MOD)) {
 
-		if (crossFading > 0) {
+		if (_G(crossFading) > 0) {
 			// It's still crossfading to the previous track
 			stop_and_destroy_channel_ex(SCHAN_MUSIC, false);
-			lock.MoveChannel(SCHAN_MUSIC, crossFading);
-			crossFading = 0;
+			lock.MoveChannel(SCHAN_MUSIC, _G(crossFading));
+			_G(crossFading) = 0;
 			update_music_volume();
-		} else if (crossFading < 0) {
+		} else if (_G(crossFading) < 0) {
 			// an old track is still fading out, no new music yet
 			// Do nothing, and keep the current crossfade step
 		} else {
 			// start crossfading
-			crossFadeStep = 0;
-			crossFadeVolumePerStep = _GP(game).options[OPT_CROSSFADEMUSIC];
-			crossFadeVolumeAtStart = calculate_max_volume();
+			_G(crossFadeStep) = 0;
+			_G(crossFadeVolumePerStep) = _GP(game).options[OPT_CROSSFADEMUSIC];
+			_G(crossFadeVolumeAtStart) = calculate_max_volume();
 		}
 		useChannel = SPECIAL_CROSSFADE_CHANNEL;
-		crossFading = useChannel;
+		_G(crossFading) = useChannel;
 	} else {
 		// crossfading is now turned off
 		stopmusic();
 		// ensure that any traces of old tunes fading are eliminated
 		// (otherwise the new track will be faded out)
-		crossFading = 0;
+		_G(crossFading) = 0;
 	}
 
 	// Just make sure, because it will be overwritten in a sec
@@ -1045,7 +1022,7 @@ static void play_new_music(int mnum, SOUNDCLIP *music) {
 
 	useChannel = prepare_for_new_music();
 	_GP(play).cur_music_number = mnum;
-	current_music_type = 0;
+	_G(current_music_type) = 0;
 
 	_GP(play).current_music_repeating = _GP(play).music_repeat;
 	// now that all the previous music is unloaded, load in the new one
@@ -1066,7 +1043,7 @@ static void play_new_music(int mnum, SOUNDCLIP *music) {
 			ch = nullptr;
 			lock.SetChannel(useChannel, nullptr);
 		} else
-			current_music_type = ch->get_sound_type();
+			_G(current_music_type) = ch->get_sound_type();
 	}
 
 	post_new_music_check(useChannel);
diff --git a/engines/ags/engine/media/audio/audio.h b/engines/ags/engine/media/audio/audio.h
index 56b84dfbec..d721cd1400 100644
--- a/engines/ags/engine/media/audio/audio.h
+++ b/engines/ags/engine/media/audio/audio.h
@@ -105,12 +105,6 @@ int         play_sound(int val1);
 
 //=============================================================================
 
-// This is an indicator of a music played by an old audio system
-// (to distinguish from the new system API); if it is not set, then old API
-// should "think" that no music is played regardless of channel state
-// TODO: refactor this and hide behind some good interface to prevent misuse!
-extern int current_music_type;
-
 void        clear_music_cache();
 void        play_next_queued();
 int         calculate_max_volume();
@@ -130,19 +124,10 @@ ScriptAudioClip *get_audio_clip_for_music(int mnum);
 SOUNDCLIP *load_music_from_disk(int mnum, bool doRepeat);
 void        newmusic(int mnum);
 
-extern volatile bool _audio_doing_crossfade;
-
 extern void cancel_scheduled_music_update();
 extern void schedule_music_update_at(AGS_Clock::time_point);
 extern void postpone_scheduled_music_update_by(std::chrono::milliseconds);
 
-// crossFading is >0 (channel number of new track), or -1 (old
-// track fading out, no new track)
-extern int crossFading, crossFadeVolumePerStep, crossFadeStep;
-extern int crossFadeVolumeAtStart;
-
-extern SOUNDCLIP *cachedQueuedMusic;
-
 } // namespace AGS3
 
 #endif
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index 3f8253e4d2..7c9b06c9ac 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -58,6 +58,7 @@
 #include "ags/engine/ac/dynobj/cc_audiochannel.h"
 #include "ags/engine/ac/dynobj/cc_audioclip.h"
 #include "ags/engine/ac/dynobj/managedobjectpool.h"
+#include "ags/engine/ac/dynobj/scriptaudiochannel.h"
 #include "ags/engine/ac/dynobj/scriptsystem.h"
 #include "ags/engine/ac/dynobj/scripthotspot.h"
 #include "ags/engine/ac/dynobj/scriptinvitem.h"
@@ -92,6 +93,7 @@ Globals::Globals() {
 	_audioChannels = new std::array<SOUNDCLIP *>(MAX_SOUND_CHANNELS + 1);
 	// TODO: double check that ambient sounds array actually needs +1
 	_ambient = new std::array<AmbientSound>(MAX_SOUND_CHANNELS + 1);
+	_scrAudioChannel = new ScriptAudioChannel[MAX_SOUND_CHANNELS + 1];
 
 	// cc_options.cpp globals
 	_ccCompOptions = SCOPT_LEFTTORIGHT;
@@ -234,6 +236,7 @@ Globals::~Globals() {
 	// audio.cpp globals
 	delete _audioChannels;
 	delete _ambient;
+	delete _scrAudioChannel;
 
 	// debug.cpp globals
 	delete[] _debug_line;
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index a70011ffc2..c7fb3e5262 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -28,6 +28,7 @@
 #include "ags/shared/gui/guimain.h"
 #include "ags/shared/script/cc_script.h"
 #include "ags/engine/main/engine.h"
+#include "ags/engine/media/audio/audiodefines.h"
 #include "ags/lib/std/array.h"
 #include "ags/lib/std/set.h"
 #include "ags/lib/allegro/color.h"
@@ -108,6 +109,7 @@ struct RoomCameraDrawData;
 struct RoomStatus;
 struct RuntimeScriptValue;
 struct ScreenOverlay;
+struct ScriptAudioChannel;
 struct ScriptDialog;
 struct ScriptGUI;
 struct ScriptHotspot;
@@ -176,6 +178,25 @@ public:
 	std::array<SOUNDCLIP *> *_audioChannels;
 	std::array<AmbientSound> *_ambient;
 
+	volatile bool _audio_doing_crossfade = false;
+	ScriptAudioChannel *_scrAudioChannel;
+	char _acaudio_buffer[256];
+	int _reserved_channel_count = 0;
+
+	// This is an indicator of a music played by an old audio system
+	// (to distinguish from the new system API)
+	int _current_music_type = 0;
+	// _G(crossFading) is >0 (channel number of new track), or -1 (old
+	// track fading out, no new track)
+	int _crossFading = 0, _crossFadeVolumePerStep = 0, _crossFadeStep = 0;
+	int _crossFadeVolumeAtStart = 0;
+	SOUNDCLIP *_cachedQueuedMusic = nullptr;
+
+	// Music update is scheduled when the voice speech stops;
+	// we do a small delay before reverting any volume adjustments
+	bool _music_update_scheduled = false;
+	uint32 _music_update_at = 0;
+
 	/**@}*/
 
 	/**


Commit: 26a69e12f7391060ae61951a7bf771eb18ed5969
    https://github.com/scummvm/scummvm/commit/26a69e12f7391060ae61951a7bf771eb18ed5969
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-03-07T16:54:20-08:00

Commit Message:
AGS: Move button.cpp globals to Globals

Changed paths:
    engines/ags/engine/ac/button.cpp
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/game/savegame_components.cpp
    engines/ags/engine/main/game_run.cpp
    engines/ags/globals.cpp
    engines/ags/globals.h


diff --git a/engines/ags/engine/ac/button.cpp b/engines/ags/engine/ac/button.cpp
index 54d2cc54e4..8c4e9bb7bb 100644
--- a/engines/ags/engine/ac/button.cpp
+++ b/engines/ags/engine/ac/button.cpp
@@ -41,11 +41,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-// *** BUTTON FUNCTIONS
-
-AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
-int numAnimButs;
-
 void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat) {
 	int guin = butt->ParentId;
 	int objn = butt->Id;
@@ -60,7 +55,7 @@ void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat)
 	// if it's already animating, stop it
 	FindAndRemoveButtonAnimation(guin, objn);
 
-	if (numAnimButs >= MAX_ANIMATING_BUTTONS)
+	if (_G(numAnimButs) >= MAX_ANIMATING_BUTTONS)
 		quit("!AnimateButton: too many animating GUI buttons at once");
 
 	int buttonId = _GP(guis)[guin].GetControlID(objn);
@@ -68,20 +63,20 @@ void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat)
 	_GP(guibuts)[buttonId].PushedImage = 0;
 	_GP(guibuts)[buttonId].MouseOverImage = 0;
 
-	animbuts[numAnimButs].ongui = guin;
-	animbuts[numAnimButs].onguibut = objn;
-	animbuts[numAnimButs].buttonid = buttonId;
-	animbuts[numAnimButs].view = view;
-	animbuts[numAnimButs].loop = loop;
-	animbuts[numAnimButs].speed = speed;
-	animbuts[numAnimButs].repeat = repeat;
-	animbuts[numAnimButs].frame = -1;
-	animbuts[numAnimButs].wait = 0;
-	numAnimButs++;
+	_G(animbuts)[_G(numAnimButs)].ongui = guin;
+	_G(animbuts)[_G(numAnimButs)].onguibut = objn;
+	_G(animbuts)[_G(numAnimButs)].buttonid = buttonId;
+	_G(animbuts)[_G(numAnimButs)].view = view;
+	_G(animbuts)[_G(numAnimButs)].loop = loop;
+	_G(animbuts)[_G(numAnimButs)].speed = speed;
+	_G(animbuts)[_G(numAnimButs)].repeat = repeat;
+	_G(animbuts)[_G(numAnimButs)].frame = -1;
+	_G(animbuts)[_G(numAnimButs)].wait = 0;
+	_G(numAnimButs)++;
 	// launch into the first frame
-	if (UpdateAnimatingButton(numAnimButs - 1)) {
+	if (UpdateAnimatingButton(_G(numAnimButs) - 1)) {
 		debug_script_warn("AnimateButton: no frames to animate");
-		StopButtonAnimation(numAnimButs - 1);
+		StopButtonAnimation(_G(numAnimButs) - 1);
 	}
 }
 
@@ -193,61 +188,58 @@ void Button_SetTextColor(GUIButton *butt, int newcol) {
 	}
 }
 
-extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
-extern int numAnimButs;
-
 // ** start animating buttons code
 
 // returns 1 if animation finished
 int UpdateAnimatingButton(int bu) {
-	if (animbuts[bu].wait > 0) {
-		animbuts[bu].wait--;
+	if (_G(animbuts)[bu].wait > 0) {
+		_G(animbuts)[bu].wait--;
 		return 0;
 	}
-	ViewStruct *tview = &_G(views)[animbuts[bu].view];
+	ViewStruct *tview = &_G(views)[_G(animbuts)[bu].view];
 
-	animbuts[bu].frame++;
+	_G(animbuts)[bu].frame++;
 
-	if (animbuts[bu].frame >= tview->loops[animbuts[bu].loop].numFrames) {
-		if (tview->loops[animbuts[bu].loop].RunNextLoop()) {
+	if (_G(animbuts)[bu].frame >= tview->loops[_G(animbuts)[bu].loop].numFrames) {
+		if (tview->loops[_G(animbuts)[bu].loop].RunNextLoop()) {
 			// go to next loop
-			animbuts[bu].loop++;
-			animbuts[bu].frame = 0;
-		} else if (animbuts[bu].repeat) {
-			animbuts[bu].frame = 0;
+			_G(animbuts)[bu].loop++;
+			_G(animbuts)[bu].frame = 0;
+		} else if (_G(animbuts)[bu].repeat) {
+			_G(animbuts)[bu].frame = 0;
 			// multi-loop anim, go back
-			while ((animbuts[bu].loop > 0) &&
-				(tview->loops[animbuts[bu].loop - 1].RunNextLoop()))
-				animbuts[bu].loop--;
+			while ((_G(animbuts)[bu].loop > 0) &&
+				(tview->loops[_G(animbuts)[bu].loop - 1].RunNextLoop()))
+				_G(animbuts)[bu].loop--;
 		} else
 			return 1;
 	}
 
-	CheckViewFrame(animbuts[bu].view, animbuts[bu].loop, animbuts[bu].frame);
+	CheckViewFrame(_G(animbuts)[bu].view, _G(animbuts)[bu].loop, _G(animbuts)[bu].frame);
 
 	// update the button's image
-	_GP(guibuts)[animbuts[bu].buttonid].Image = tview->loops[animbuts[bu].loop].frames[animbuts[bu].frame].pic;
-	_GP(guibuts)[animbuts[bu].buttonid].CurrentImage = _GP(guibuts)[animbuts[bu].buttonid].Image;
-	_GP(guibuts)[animbuts[bu].buttonid].PushedImage = 0;
-	_GP(guibuts)[animbuts[bu].buttonid].MouseOverImage = 0;
+	_GP(guibuts)[_G(animbuts)[bu].buttonid].Image = tview->loops[_G(animbuts)[bu].loop].frames[_G(animbuts)[bu].frame].pic;
+	_GP(guibuts)[_G(animbuts)[bu].buttonid].CurrentImage = _GP(guibuts)[_G(animbuts)[bu].buttonid].Image;
+	_GP(guibuts)[_G(animbuts)[bu].buttonid].PushedImage = 0;
+	_GP(guibuts)[_G(animbuts)[bu].buttonid].MouseOverImage = 0;
 	guis_need_update = 1;
 
-	animbuts[bu].wait = animbuts[bu].speed + tview->loops[animbuts[bu].loop].frames[animbuts[bu].frame].speed;
+	_G(animbuts)[bu].wait = _G(animbuts)[bu].speed + tview->loops[_G(animbuts)[bu].loop].frames[_G(animbuts)[bu].frame].speed;
 	return 0;
 }
 
 void StopButtonAnimation(int idxn) {
-	numAnimButs--;
-	for (int aa = idxn; aa < numAnimButs; aa++) {
-		animbuts[aa] = animbuts[aa + 1];
+	_G(numAnimButs)--;
+	for (int aa = idxn; aa < _G(numAnimButs); aa++) {
+		_G(animbuts)[aa] = _G(animbuts)[aa + 1];
 	}
 }
 
 // Returns the index of the AnimatingGUIButton object corresponding to the
 // given button ID; returns -1 if no such animation exists
 int FindAnimatedButton(int guin, int objn) {
-	for (int i = 0; i < numAnimButs; ++i) {
-		if (animbuts[i].ongui == guin && animbuts[i].onguibut == objn)
+	for (int i = 0; i < _G(numAnimButs); ++i) {
+		if (_G(animbuts)[i].ongui == guin && _G(animbuts)[i].onguibut == objn)
 			return i;
 	}
 	return -1;
@@ -273,17 +265,17 @@ bool Button_IsAnimating(GUIButton *butt) {
 // zero-based index and 0 in case of no animation.
 int Button_GetAnimView(GUIButton *butt) {
 	int idx = FindAnimatedButton(butt->ParentId, butt->Id);
-	return idx >= 0 ? animbuts[idx].view + 1 : 0;
+	return idx >= 0 ? _G(animbuts)[idx].view + 1 : 0;
 }
 
 int Button_GetAnimLoop(GUIButton *butt) {
 	int idx = FindAnimatedButton(butt->ParentId, butt->Id);
-	return idx >= 0 ? animbuts[idx].loop : 0;
+	return idx >= 0 ? _G(animbuts)[idx].loop : 0;
 }
 
 int Button_GetAnimFrame(GUIButton *butt) {
 	int idx = FindAnimatedButton(butt->ParentId, butt->Id);
-	return idx >= 0 ? animbuts[idx].frame : 0;
+	return idx >= 0 ? _G(animbuts)[idx].frame : 0;
 }
 
 int Button_GetTextAlignment(GUIButton *butt) {
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index ea0c633f4f..f640febca9 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -120,9 +120,6 @@ extern int ifacepopped;  // currently displayed pop-up GUI (-1 if none)
 extern int mouse_on_iface;   // mouse cursor is over this interface
 extern int mouse_ifacebut_xoffs, mouse_ifacebut_yoffs;
 
-extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
-extern int numAnimButs;
-
 #if AGS_PLATFORM_OS_IOS || AGS_PLATFORM_OS_ANDROID
 extern int _G(psp_gfx_renderer);
 #endif
@@ -1191,8 +1188,8 @@ void restore_game_more_dynamic_values(Stream *in) {
 
 void ReadAnimatedButtons_Aligned(Stream *in) {
 	AlignedStream align_s(in, Shared::kAligned_Read);
-	for (int i = 0; i < numAnimButs; ++i) {
-		animbuts[i].ReadFromFile(&align_s);
+	for (int i = 0; i < _G(numAnimButs); ++i) {
+		_G(animbuts)[i].ReadFromFile(&align_s);
 		align_s.Reset();
 	}
 }
@@ -1207,7 +1204,7 @@ HSaveError restore_game_gui(Stream *in, int numGuisWas) {
 		return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of GUI.");
 	}
 
-	numAnimButs = in->ReadInt32();
+	_G(numAnimButs) = in->ReadInt32();
 	ReadAnimatedButtons_Aligned(in);
 	return HSaveError::None();
 }
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index d45e138c59..4cbc5cc3e2 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -65,9 +65,6 @@ using namespace Shared;
 
 extern color palette[256];
 extern DialogTopic *dialog;
-extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
-extern int numAnimButs;
-
 extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
 extern Bitmap *raw_saved_screen;
 
@@ -568,9 +565,9 @@ HSaveError WriteGUI(PStream out) {
 
 	// Animated buttons
 	WriteFormatTag(out, "AnimatedButtons");
-	out->WriteInt32(numAnimButs);
-	for (int i = 0; i < numAnimButs; ++i)
-		animbuts[i].WriteToFile(out.get());
+	out->WriteInt32(_G(numAnimButs));
+	for (int i = 0; i < _G(numAnimButs); ++i)
+		_G(animbuts)[i].WriteToFile(out.get());
 	return HSaveError::None();
 }
 
@@ -633,9 +630,9 @@ HSaveError ReadGUI(PStream in, int32_t cmp_ver, const PreservedParams &pp, Resto
 	int anim_count = in->ReadInt32();
 	if (!AssertCompatLimit(err, anim_count, MAX_ANIMATING_BUTTONS, "animated buttons"))
 		return err;
-	numAnimButs = anim_count;
-	for (int i = 0; i < numAnimButs; ++i)
-		animbuts[i].ReadFromFile(in.get());
+	_G(numAnimButs) = anim_count;
+	for (int i = 0; i < _G(numAnimButs); ++i)
+		_G(animbuts)[i].ReadFromFile(in.get());
 	return err;
 }
 
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index c8fbee1ae3..b0db30fd29 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -73,8 +73,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
-extern int numAnimButs;
 extern int mouse_on_iface;   // mouse cursor is over this interface
 extern int ifacepopped;
 extern int proper_exit, our_eip;
@@ -603,7 +601,7 @@ static void game_loop_update_animated_buttons() {
 	// update animating GUI buttons
 	// this bit isn't in update_stuff because it always needs to
 	// happen, even when the game is paused
-	for (int aa = 0; aa < numAnimButs; aa++) {
+	for (int aa = 0; aa < _G(numAnimButs); aa++) {
 		if (UpdateAnimatingButton(aa)) {
 			StopButtonAnimation(aa);
 			aa--;
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index 7c9b06c9ac..0a21d46f34 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -70,6 +70,7 @@
 #include "ags/engine/debugging/debugger.h"
 #include "ags/engine/debugging/logfile.h"
 #include "ags/engine/debugging/messagebuffer.h"
+#include "ags/engine/gui/animatingguibutton.h"
 #include "ags/engine/main/graphics_mode.h"
 #include "ags/engine/media/audio/ambientsound.h"
 #include "ags/engine/media/audio/audiodefines.h"
@@ -89,12 +90,15 @@ Globals::Globals() {
 
 	Common::fill(&_mousecurs[0], &_mousecurs[MAXCURSORS], nullptr);
 
-	// audio.cpp
+	// audio.cpp globals
 	_audioChannels = new std::array<SOUNDCLIP *>(MAX_SOUND_CHANNELS + 1);
 	// TODO: double check that ambient sounds array actually needs +1
 	_ambient = new std::array<AmbientSound>(MAX_SOUND_CHANNELS + 1);
 	_scrAudioChannel = new ScriptAudioChannel[MAX_SOUND_CHANNELS + 1];
 
+	// button.cpp globals
+	_animbuts = new AnimatingGUIButton[MAX_ANIMATING_BUTTONS];
+
 	// cc_options.cpp globals
 	_ccCompOptions = SCOPT_LEFTTORIGHT;
 
@@ -238,6 +242,9 @@ Globals::~Globals() {
 	delete _ambient;
 	delete _scrAudioChannel;
 
+	// button.cpp globals
+	delete[] _animbuts;
+
 	// debug.cpp globals
 	delete[] _debug_line;
 	delete _DebugMsgBuff;
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index c7fb3e5262..5dc330784e 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -79,6 +79,7 @@ class WFNFontRenderer;
 
 struct ActiveDisplaySetting;
 struct AmbientSound;
+struct AnimatingGUIButton;
 struct CCAudioChannel;
 struct CCAudioClip;
 struct CCCharacter;
@@ -199,6 +200,16 @@ public:
 
 	/**@}*/
 
+	/**
+	 * \defgroup button globals
+	 * @{
+	 */
+
+	AnimatingGUIButton *_animbuts;
+	int _numAnimButs = 0;
+
+	/**@}*/
+
 	/**
 	 * \defgroup cc_error globals
 	 * @{


Commit: 37b563ef35587dacd772016e2e32584614be92e0
    https://github.com/scummvm/scummvm/commit/37b563ef35587dacd772016e2e32584614be92e0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-03-07T19:23:24-08:00

Commit Message:
AGS: Move game globals to Globals

Changed paths:
    engines/ags/ags.cpp
    engines/ags/engine/ac/cdaudio.cpp
    engines/ags/engine/ac/character.cpp
    engines/ags/engine/ac/characterinfo_engine.cpp
    engines/ags/engine/ac/datetime.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/event.cpp
    engines/ags/engine/ac/file.cpp
    engines/ags/engine/ac/game.cpp
    engines/ags/engine/ac/game.h
    engines/ags/engine/ac/global_character.cpp
    engines/ags/engine/ac/global_debug.cpp
    engines/ags/engine/ac/global_game.cpp
    engines/ags/engine/ac/global_hotspot.cpp
    engines/ags/engine/ac/global_object.cpp
    engines/ags/engine/ac/global_region.cpp
    engines/ags/engine/ac/global_room.cpp
    engines/ags/engine/ac/global_screen.cpp
    engines/ags/engine/ac/global_translation.cpp
    engines/ags/engine/ac/global_walkbehind.cpp
    engines/ags/engine/ac/hotspot.cpp
    engines/ags/engine/ac/invwindow.cpp
    engines/ags/engine/ac/mouse.cpp
    engines/ags/engine/ac/object.cpp
    engines/ags/engine/ac/overlay.cpp
    engines/ags/engine/ac/region.cpp
    engines/ags/engine/ac/room.cpp
    engines/ags/engine/ac/screen.cpp
    engines/ags/engine/ac/sprite.cpp
    engines/ags/engine/ac/sys_events.cpp
    engines/ags/engine/ac/system.cpp
    engines/ags/engine/ac/walkablearea.cpp
    engines/ags/engine/debugging/debug.cpp
    engines/ags/engine/debugging/debug_log.h
    engines/ags/engine/debugging/filebasedagsdebugger.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/ali3dscummvm.cpp
    engines/ags/engine/main/config.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/engine/main/engine_setup.cpp
    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/platform/base/agsplatformdriver.cpp
    engines/ags/engine/platform/base/agsplatformdriver.h
    engines/ags/engine/platform/windows/acplwin.cpp
    engines/ags/engine/platform/windows/win_ex_handling.cpp
    engines/ags/engine/script/script.cpp
    engines/ags/globals.h
    engines/ags/plugins/agsplugin.cpp
    engines/ags/shared/font/wfnfontrenderer.cpp


diff --git a/engines/ags/ags.cpp b/engines/ags/ags.cpp
index 97ee0819f6..01f9533ef4 100644
--- a/engines/ags/ags.cpp
+++ b/engines/ags/ags.cpp
@@ -69,8 +69,7 @@ using namespace Engine;
 
 extern HSaveError load_game(int slotNumber, bool &data_overwritten);
 
-extern int our_eip;
-extern AGSPlatformDriver *platform;
+
 extern int convert_16bit_bgr;
 
 // this needs to be updated if the "play" struct changes
@@ -88,13 +87,13 @@ extern int convert_16bit_bgr;
 extern void quit_free();
 
 void main_pre_init() {
-	our_eip = -999;
+	_G(our_eip) = -999;
 	Shared::AssetManager::SetSearchPriority(Shared::kAssetPriorityDir);
 	_GP(play).takeover_data = 0;
 }
 
 void main_create_platform_driver() {
-	platform = AGSPlatformDriver::GetDriver();
+	_G(platform) = AGSPlatformDriver::GetDriver();
 }
 
 void main_init(int argc, const char *argv[]) {
@@ -292,6 +291,14 @@ AGSEngine::AGSEngine(OSystem *syst, const AGSGameDescription *gameDesc) : Engine
 }
 
 AGSEngine::~AGSEngine() {
+	if (_G(proper_exit) == 0) {
+		_G(platform)->DisplayAlert("Error: the program has exited without requesting it.\n"
+			"Program pointer: %+03d  (write this number down), ACI version %s\n"
+			"If you see a list of numbers above, please write them down and contact\n"
+			"developers. Otherwise, note down any other information displayed.",
+			_G(our_eip), _G(EngineVersion).LongString.GetCStr());
+	}
+
 	delete _screen;
 	delete _rawScreen;
 	delete _events;
@@ -340,7 +347,7 @@ Common::Error AGSEngine::run() {
 		return Common::kUnknownError;
 
 	if (_G(justDisplayVersion)) {
-		AGS3::platform->WriteStdOut(AGS3::get_engine_string());
+		_G(platform)->WriteStdOut(AGS3::get_engine_string());
 		return Common::kNoError;
 	}
 
@@ -350,7 +357,7 @@ Common::Error AGSEngine::run() {
 	}
 
 	if (!_G(justTellInfo))
-		AGS3::platform->SetGUIMode(true);
+		_G(platform)->SetGUIMode(true);
 	AGS3::init_debug(startup_opts, _G(justTellInfo));
 	AGS3::Debug::Printf("%s", AGS3::get_engine_string().GetNullableCStr());
 
diff --git a/engines/ags/engine/ac/cdaudio.cpp b/engines/ags/engine/ac/cdaudio.cpp
index fc8cbd26c6..6941d0cb11 100644
--- a/engines/ags/engine/ac/cdaudio.cpp
+++ b/engines/ags/engine/ac/cdaudio.cpp
@@ -22,6 +22,7 @@
 
 #include "ags/engine/ac/cdaudio.h"
 #include "ags/engine/platform/base/agsplatformdriver.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
@@ -31,7 +32,7 @@ int need_to_stop_cd = 0;
 
 int init_cd_player() {
 	use_cdplayer = 0;
-	return platform->InitializeCDPlayer();
+	return _G(platform)->InitializeCDPlayer();
 }
 
 int cd_manager(int cmdd, int datt) {
@@ -42,7 +43,7 @@ int cd_manager(int cmdd, int datt) {
 	if (cmdd == 0) return use_cdplayer;
 	if (use_cdplayer == 0) return 0; // ignore other commands
 
-	return platform->CDPlayerCommand(cmdd, datt);
+	return _G(platform)->CDPlayerCommand(cmdd, datt);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index 8a4729b83a..d3f36a0f39 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -79,14 +79,11 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern int displayed_room, starting_room;
-extern RoomObject *objs;
 extern Bitmap *walkable_areas_temp;
 extern IGraphicsDriver *gfxDriver;
 extern Bitmap **actsps;
 extern int said_speech_line;
 extern int said_text;
-extern int our_eip;
 
 //--------------------------------
 
@@ -163,7 +160,7 @@ void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addInd
 
 void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) {
 
-	if (chaa->room != displayed_room)
+	if (chaa->room != _G(displayed_room))
 		quit("!MoveCharacterPath: specified character not in current room");
 
 	// not already walking, so just do a normal move
@@ -214,23 +211,23 @@ void Character_ChangeRoomAutoPosition(CharacterInfo *chaa, int room, int newPos)
 		quit("!Character.ChangeRoomAutoPosition can only be used with the player character.");
 	}
 
-	new_room_pos = newPos;
+	_G(new_room_pos) = newPos;
 
-	if (new_room_pos == 0) {
+	if (_G(new_room_pos) == 0) {
 		// auto place on other side of screen
 		if (chaa->x <= _GP(thisroom).Edges.Left + 10)
-			new_room_pos = 2000;
+			_G(new_room_pos) = 2000;
 		else if (chaa->x >= _GP(thisroom).Edges.Right - 10)
-			new_room_pos = 1000;
+			_G(new_room_pos) = 1000;
 		else if (chaa->y <= _GP(thisroom).Edges.Top + 10)
-			new_room_pos = 3000;
+			_G(new_room_pos) = 3000;
 		else if (chaa->y >= _GP(thisroom).Edges.Bottom - 10)
-			new_room_pos = 4000;
+			_G(new_room_pos) = 4000;
 
-		if (new_room_pos < 3000)
-			new_room_pos += chaa->y;
+		if (_G(new_room_pos) < 3000)
+			_G(new_room_pos) += chaa->y;
 		else
-			new_room_pos += chaa->x;
+			_G(new_room_pos) += chaa->x;
 	}
 	NewRoom(room);
 }
@@ -258,7 +255,7 @@ void Character_ChangeRoomSetLoop(CharacterInfo *chaa, int room, int x, int y, in
 	}
 
 	if ((x != SCR_NO_VALUE) && (y != SCR_NO_VALUE)) {
-		new_room_pos = 0;
+		_G(new_room_pos) = 0;
 
 		if (loaded_game_file_version <= kGameVersion_272) {
 			// Set position immediately on 2.x.
@@ -267,9 +264,9 @@ void Character_ChangeRoomSetLoop(CharacterInfo *chaa, int room, int x, int y, in
 		} else {
 			// don't check X or Y bounds, so that they can do a
 			// walk-in animation if they want
-			new_room_x = x;
-			new_room_y = y;
-			if (direction != SCR_NO_VALUE) new_room_loop = direction;
+			_G(new_room_x) = x;
+			_G(new_room_y) = y;
+			if (direction != SCR_NO_VALUE) _G(new_room_loop) = direction;
 		}
 	}
 
@@ -430,7 +427,7 @@ void Character_FaceObject(CharacterInfo *char1, ScriptObject *obj, int blockingS
 	if (obj == nullptr)
 		quit("!FaceObject: invalid object specified");
 
-	FaceLocationXY(char1, objs[obj->id].x, objs[obj->id].y, blockingStyle);
+	FaceLocationXY(char1, _G(objs)[obj->id].x, _G(objs)[obj->id].y, blockingStyle);
 }
 
 void Character_FaceCharacter(CharacterInfo *char1, CharacterInfo *char2, int blockingStyle) {
@@ -509,16 +506,16 @@ int Character_IsCollidingWithObject(CharacterInfo *chin, ScriptObject *objid) {
 	if (objid == nullptr)
 		quit("!AreCharObjColliding: invalid object number");
 
-	if (chin->room != displayed_room)
+	if (chin->room != _G(displayed_room))
 		return 0;
-	if (objs[objid->id].on != 1)
+	if (_G(objs)[objid->id].on != 1)
 		return 0;
 
 	Bitmap *checkblk = GetObjectImage(objid->id, nullptr);
 	int objWidth = checkblk->GetWidth();
 	int objHeight = checkblk->GetHeight();
-	int o1x = objs[objid->id].x;
-	int o1y = objs[objid->id].y - game_to_data_coord(objHeight);
+	int o1x = _G(objs)[objid->id].x;
+	int o1y = _G(objs)[objid->id].y - game_to_data_coord(objHeight);
 
 	Bitmap *charpic = GetCharacterImage(chin->index_id, nullptr);
 
@@ -704,7 +701,7 @@ void Character_LoseInventory(CharacterInfo *chap, ScriptInvItem *invi) {
 }
 
 void Character_PlaceOnWalkableArea(CharacterInfo *chap) {
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		quit("!Character.PlaceOnWalkableArea: no room is currently loaded");
 
 	find_nearest_walkable_area(&chap->x, &chap->y);
@@ -772,16 +769,16 @@ void Character_SetAsPlayer(CharacterInfo *chaa) {
 	debug_script_log("%s is new player character", playerchar->scrname);
 
 	// Within game_start, return now
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		return;
 
 	// Ignore invalid room numbers for the character and just place him in
 	// the current room for 2.x. Following script calls to NewRoom() will
 	// make sure this still works as intended.
 	if ((loaded_game_file_version <= kGameVersion_272) && (playerchar->room < 0))
-		playerchar->room = displayed_room;
+		playerchar->room = _G(displayed_room);
 
-	if (displayed_room != playerchar->room)
+	if (_G(displayed_room) != playerchar->room)
 		NewRoom(playerchar->room);
 	else   // make sure it doesn't run the region interactions
 		_GP(play).player_on_region = GetRegionIDAtRoom(playerchar->x, playerchar->y);
@@ -918,7 +915,7 @@ void Character_StopMoving(CharacterInfo *charp) {
 	}
 	if ((charp->walking > 0) && (charp->walking < TURNING_AROUND)) {
 		// if it's not a MoveCharDirect, make sure they end up on a walkable area
-		if ((_G(mls)[charp->walking].direct == 0) && (charp->room == displayed_room))
+		if ((_G(mls)[charp->walking].direct == 0) && (charp->room == _G(displayed_room)))
 			Character_PlaceOnWalkableArea(charp);
 
 		debug_script_log("%s: stop moving", charp->scrname);
@@ -997,7 +994,7 @@ void Character_Move(CharacterInfo *chaa, int x, int y, int blocking, int direct)
 
 void Character_WalkStraight(CharacterInfo *chaa, int xx, int yy, int blocking) {
 
-	if (chaa->room != displayed_room)
+	if (chaa->room != _G(displayed_room))
 		quit("!MoveCharacterStraight: specified character not in current room");
 
 	Character_StopMoving(chaa);
@@ -1602,7 +1599,7 @@ 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 = &_GP(game).chars[chac];
-	if (chin->room != displayed_room)
+	if (chin->room != _G(displayed_room))
 		quit("!MoveCharacter: character not in current room");
 
 	chin->flags &= ~CHF_MOVENOTWALK;
@@ -1792,7 +1789,7 @@ int has_hit_another_character(int sourceChar) {
 
 	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 (_GP(game).chars[ww].room != _G(displayed_room)) continue;
 		if (ww == sourceChar) continue;
 		if (_GP(game).chars[ww].flags & CHF_NOBLOCKING) continue;
 
@@ -2133,7 +2130,7 @@ 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 < _GP(game).numcharacters; cc++) {
-		if (_GP(game).chars[cc].room != displayed_room) continue;
+		if (_GP(game).chars[cc].room != _G(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;
@@ -2313,7 +2310,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 
 	// the strings are pre-translated
 	//texx = get_translation(texx);
-	our_eip = 150;
+	_G(our_eip) = 150;
 
 	int isPause = 1;
 	// if the message is all .'s, don't display anything
@@ -2328,7 +2325,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	_GP(play).speech_in_post_state = false;
 
 	if (isPause) {
-		postpone_scheduled_music_update_by(std::chrono::milliseconds(_GP(play).messagetime * 1000 / frames_per_second));
+		postpone_scheduled_music_update_by(std::chrono::milliseconds(_GP(play).messagetime * 1000 / _G(frames_per_second)));
 		GameLoopUntilValueIsNegative(&_GP(play).messagetime);
 		return;
 	}
@@ -2345,7 +2342,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	if (bwidth < 0)
 		bwidth = ui_view.GetWidth() / 2 + ui_view.GetWidth() / 4;
 
-	our_eip = 151;
+	_G(our_eip) = 151;
 
 	int useview = speakingChar->talkview;
 	if (isThought) {
@@ -2355,7 +2352,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			useview = -1;
 		// speech bubble can shrink to fit
 		allowShrink = 1;
-		if (speakingChar->room != displayed_room) {
+		if (speakingChar->room != _G(displayed_room)) {
 			// not in room, centre it
 			xx = -1;
 			yy = -1;
@@ -2379,7 +2376,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 
 	if (_GP(game).options[OPT_SPEECHTYPE] == 3)
 		remove_screen_overlay(OVER_COMPLETE);
-	our_eip = 1500;
+	_G(our_eip) = 1500;
 
 	if (_GP(game).options[OPT_SPEECHTYPE] == 0)
 		allowShrink = 1;
@@ -2396,14 +2393,14 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	if (speakingChar->flags & CHF_FIXVIEW)
 		viewWasLocked = 1;
 
-	/*if ((speakingChar->room == displayed_room) ||
+	/*if ((speakingChar->room == _G(displayed_room)) ||
 	((useview >= 0) && (_GP(game).options[OPT_SPEECHTYPE] > 0)) ) {*/
 
-	if (speakingChar->room == displayed_room) {
+	if (speakingChar->room == _G(displayed_room)) {
 		// If the character is in this room, go for it - otherwise
 		// run the "else" clause which  does text in the middle of
 		// the screen.
-		our_eip = 1501;
+		_G(our_eip) = 1501;
 
 		if (speakingChar->walking)
 			StopMoving(aschar);
@@ -2425,7 +2422,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			quitprintf("Unable to display speech because the character %s has an invalid view frame (View %d, loop %d, frame %d)", speakingChar->scrname, speakingChar->view + 1, speakingChar->loop, speakingChar->frame);
 		}
 
-		our_eip = 1504;
+		_G(our_eip) = 1504;
 
 		// Calculate speech position based on character's position on screen
 		auto view = FindNearestViewport(aschar);
@@ -2446,7 +2443,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 		if (tdyp < 5)
 			tdyp = 5;
 
-		our_eip = 152;
+		_G(our_eip) = 152;
 
 		if ((useview >= 0) && (_GP(game).options[OPT_SPEECHTYPE] > 0)) {
 			// Sierra-style close-up portrait
@@ -2534,7 +2531,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			if (widd > 0)
 				bwidth = widd - bigx;
 
-			our_eip = 153;
+			_G(our_eip) = 153;
 			int ovr_yp = get_fixed_pixel_size(20);
 			int view_frame_x = 0;
 			int view_frame_y = 0;
@@ -2640,7 +2637,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 			overlayPositionFixed = true;
 		} else if (useview >= 0) {
 			// Lucasarts-style speech
-			our_eip = 154;
+			_G(our_eip) = 154;
 
 			oldview = speakingChar->view;
 			oldloop = speakingChar->loop;
@@ -2698,9 +2695,9 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	if (isThought)
 		char_thinking = aschar;
 
-	our_eip = 155;
+	_G(our_eip) = 155;
 	_display_at(tdxp, tdyp, bwidth, texx, DISPLAYTEXT_SPEECH, textcol, isThought, allowShrink, overlayPositionFixed);
-	our_eip = 156;
+	_G(our_eip) = 156;
 	if ((_GP(play).in_conversation > 0) && (_GP(game).options[OPT_SPEECHTYPE] == 3))
 		closeupface = nullptr;
 	if (closeupface != nullptr)
@@ -2708,7 +2705,7 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
 	mark_screen_dirty();
 	face_talking = -1;
 	facetalkchar = nullptr;
-	our_eip = 157;
+	_G(our_eip) = 157;
 	if (oldview >= 0) {
 		speakingChar->flags &= ~CHF_FIXVIEW;
 		if (viewWasLocked)
diff --git a/engines/ags/engine/ac/characterinfo_engine.cpp b/engines/ags/engine/ac/characterinfo_engine.cpp
index f0b546bd90..a1b25d5f39 100644
--- a/engines/ags/engine/ac/characterinfo_engine.cpp
+++ b/engines/ags/engine/ac/characterinfo_engine.cpp
@@ -43,7 +43,7 @@ using namespace AGS::Shared;
 
 
 
-extern int displayed_room;
+
 
 extern int char_speaking;
 
@@ -164,7 +164,7 @@ int CharacterInfo::update_character_walking(CharacterExtras *chex) {
 }
 
 void CharacterInfo::update_character_moving(int &char_index, CharacterExtras *chex, int &doing_nothing) {
-	if ((walking > 0) && (room == displayed_room)) {
+	if ((walking > 0) && (room == _G(displayed_room))) {
 		if (walkwait > 0) walkwait--;
 		else {
 			flags &= ~CHF_AWAITINGMOVE;
@@ -261,7 +261,7 @@ int CharacterInfo::update_character_animating(int &aa, int &doing_nothing) {
 	// idleleft is <0 while idle view is playing (.animating is 0)
 	if (((animating != 0) || (idleleft < 0)) &&
 		((walking == 0) || ((flags & CHF_MOVENOTWALK) != 0)) &&
-		(room == displayed_room)) {
+		(room == _G(displayed_room))) {
 		doing_nothing = 0;
 		// idle anim doesn't count as doing something
 		if (idleleft < 0)
@@ -400,7 +400,7 @@ void CharacterInfo::update_character_follower(int &aa, int &numSheep, int *follo
 			prevroom = room;
 			room = _GP(game).chars[following].room;
 
-			if (room == displayed_room) {
+			if (room == _G(displayed_room)) {
 				// only move to the room-entered position if coming into
 				// the current room
 				if (_GP(play).entered_at_x > (_GP(thisroom).Width - 8)) {
@@ -425,7 +425,7 @@ void CharacterInfo::update_character_follower(int &aa, int &numSheep, int *follo
 					doing_nothing = 0;
 				}
 			}
-		} else if (room != displayed_room) {
+		} else if (room != _G(displayed_room)) {
 			// if the characetr is following another character and
 			// neither is in the current room, don't try to move
 		} else if ((abs(_GP(game).chars[following].x - x) > distaway + 30) |
@@ -449,7 +449,7 @@ void CharacterInfo::update_character_idle(CharacterExtras *chex, int &doing_noth
 	// currently playing idle anim
 	else if (idleleft < 0);
 	// not in the current room
-	else if (room != displayed_room);
+	else if (room != _G(displayed_room));
 	// they are moving or animating (or the view is locked), so
 	// reset idle timeout
 	else if ((doing_nothing == 0) || ((flags & CHF_FIXVIEW) != 0))
diff --git a/engines/ags/engine/ac/datetime.cpp b/engines/ags/engine/ac/datetime.cpp
index fea7a76180..0c8c0af3c5 100644
--- a/engines/ags/engine/ac/datetime.cpp
+++ b/engines/ags/engine/ac/datetime.cpp
@@ -26,13 +26,14 @@
 #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 {
 
 ScriptDateTime *DateTime_Now_Core() {
 	ScriptDateTime *sdt = new ScriptDateTime();
 
-	platform->GetSystemTime(sdt);
+	_G(platform)->GetSystemTime(sdt);
 
 	return sdt;
 }
diff --git a/engines/ags/engine/ac/dialog.cpp b/engines/ags/engine/ac/dialog.cpp
index ab1dd8fddf..a8a54dd20c 100644
--- a/engines/ags/engine/ac/dialog.cpp
+++ b/engines/ags/engine/ac/dialog.cpp
@@ -70,9 +70,8 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern int in_new_room;
 extern CharacterInfo *playerchar;
-extern AGSPlatformDriver *platform;
+
 extern int cur_mode, cur_cursor;
 extern IGraphicsDriver *gfxDriver;
 
@@ -268,7 +267,7 @@ int run_dialog_script(DialogTopic *dtpp, int dialogID, int offse, int optionInde
 			case DCMD_NEWROOM:
 				get_dialog_script_parameters(script, &param1, nullptr);
 				NewRoom(param1);
-				in_new_room = 1;
+				_G(in_new_room) = 1;
 				result = RUN_DIALOG_STOP_DIALOG;
 				script_running = false;
 				break;
@@ -301,7 +300,7 @@ int run_dialog_script(DialogTopic *dtpp, int dialogID, int offse, int optionInde
 		}
 	}
 
-	if (in_new_room > 0)
+	if (_G(in_new_room) > 0)
 		return RUN_DIALOG_STOP_DIALOG;
 
 	if (said_speech_line > 0) {
diff --git a/engines/ags/engine/ac/display.cpp b/engines/ags/engine/ac/display.cpp
index 594804287e..97a18a590d 100644
--- a/engines/ags/engine/ac/display.cpp
+++ b/engines/ags/engine/ac/display.cpp
@@ -63,7 +63,7 @@ using namespace AGS::Shared::BitmapHelper;
 
 
 extern int longestline;
-extern AGSPlatformDriver *platform;
+
 extern int loops_per_character;
 
 
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 6219bfdcc7..819b1cc71f 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -89,7 +89,7 @@ extern "C" void ios_render();
 #endif
 
 extern int convert_16bit_bgr;
-extern AGSPlatformDriver *platform;
+
 extern char noWalkBehindsAtAll;
 extern unsigned int loopcounter;
 extern char *walkBehindExists;  // whether a WB area is in this column
@@ -101,12 +101,6 @@ extern int walkBehindsCachedForBgNum;
 extern WalkBehindMethodEnum walkBehindMethod;
 extern int walk_behind_baselines_changed;
 
-extern RoomStatus *croom;
-extern int our_eip;
-extern int in_new_room;
-extern RoomObject *objs;
-
-extern int displayed_room;
 extern CharacterExtras *charextra;
 extern CharacterInfo *playerchar;
 extern int eip_guinum;
@@ -696,7 +690,7 @@ void render_to_screen() {
 
 			succeeded = true;
 /*		} catch (Ali3DFullscreenLostException) {
-			platform->Delay(500);
+			_G(platform)->Delay(500);
 		}*/
 	}
 }
@@ -830,7 +824,7 @@ int sort_out_walk_behinds(Bitmap *sprit, int xx, int yy, int basel, Bitmap *copy
 			// since we know it's 8-bit bitmap
 			tmm = _GP(thisroom).WalkBehindMask->GetScanLine(rr + yy)[ee + xx];
 			if (tmm < 1) continue;
-			if (croom->walkbehind_base[tmm] <= basel) continue;
+			if (_G(croom)->walkbehind_base[tmm] <= basel) continue;
 
 			if (copyPixelsFrom != nullptr) {
 				if (spcoldep <= 8) {
@@ -1016,7 +1010,7 @@ void draw_sprite_list() {
 		for (int ee = 1; ee < MAX_WALK_BEHINDS; ee++) {
 			if (walkBehindBitmap[ee] != nullptr) {
 				add_to_sprite_list(walkBehindBitmap[ee], walkBehindLeft[ee], walkBehindTop[ee],
-				                   croom->walkbehind_base[ee], 0, -1, true);
+				                   _G(croom)->walkbehind_base[ee], 0, -1, true);
 			}
 		}
 	}
@@ -1219,11 +1213,11 @@ int scale_and_flip_sprite(int useindx, int coldept, int zoom_level,
 	if (zoom_level != 100) {
 		// Scaled character
 
-		our_eip = 334;
+		_G(our_eip) = 334;
 
 		// Ensure that anti-aliasing routines have a palette to
 		// use for mapping while faded out
-		if (in_new_room)
+		if (_G(in_new_room))
 			select_palette(palette);
 
 
@@ -1262,13 +1256,13 @@ int scale_and_flip_sprite(int useindx, int coldept, int zoom_level,
 		else
 		->StretchBlt(actsps[useindx],_GP(spriteset)[sppic],0,0,newwidth,newheight);
 		*/
-		if (in_new_room)
+		if (_G(in_new_room))
 			unselect_palette();
 
 	} else {
 		// Not a scaled character, draw at normal size
 
-		our_eip = 339;
+		_G(our_eip) = 339;
 
 		if (isMirrored)
 			active_spr->FlipBlt(_GP(spriteset)[sppic], 0, 0, Shared::kBitmap_HFlip);
@@ -1289,32 +1283,32 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 	int useindx = aa;
 	bool hardwareAccelerated = !alwaysUseSoftware && gfxDriver->HasAcceleratedTransform();
 
-	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);
+	if (_GP(spriteset)[_G(objs)[aa].num] == nullptr)
+		quitprintf("There was an error drawing object %d. Its current sprite, %d, is invalid.", aa, _G(objs)[aa].num);
 
-	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 coldept = _GP(spriteset)[_G(objs)[aa].num]->GetColorDepth();
+	int sprwidth = _GP(game).SpriteInfos[_G(objs)[aa].num].Width;
+	int sprheight = _GP(game).SpriteInfos[_G(objs)[aa].num].Height;
 
 	int tint_red, tint_green, tint_blue;
 	int tint_level, tint_light, light_level;
 	int zoom_level = 100;
 
 	// calculate the zoom level
-	if ((objs[aa].flags & OBJF_USEROOMSCALING) == 0) {
-		zoom_level = objs[aa].zoom;
+	if ((_G(objs)[aa].flags & OBJF_USEROOMSCALING) == 0) {
+		zoom_level = _G(objs)[aa].zoom;
 	} else {
-		int onarea = get_walkable_area_at_location(objs[aa].x, objs[aa].y);
+		int onarea = get_walkable_area_at_location(_G(objs)[aa].x, _G(objs)[aa].y);
 		if ((onarea <= 0) && (_GP(thisroom).WalkAreas[0].ScalingFar == 0)) {
 			// just off the edge of an area -- use the scaling we had
 			// while on the area
-			zoom_level = objs[aa].zoom;
+			zoom_level = _G(objs)[aa].zoom;
 		} else
-			zoom_level = get_area_scaling(onarea, objs[aa].x, objs[aa].y);
+			zoom_level = get_area_scaling(onarea, _G(objs)[aa].x, _G(objs)[aa].y);
 	}
 	if (zoom_level != 100)
-		scale_sprite_size(objs[aa].num, zoom_level, &sprwidth, &sprheight);
-	objs[aa].zoom = zoom_level;
+		scale_sprite_size(_G(objs)[aa].num, zoom_level, &sprwidth, &sprheight);
+	_G(objs)[aa].zoom = zoom_level;
 
 	// save width/height into parameters if requested
 	if (drawnWidth)
@@ -1322,44 +1316,44 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 	if (drawnHeight)
 		*drawnHeight = sprheight;
 
-	objs[aa].last_width = sprwidth;
-	objs[aa].last_height = sprheight;
+	_G(objs)[aa].last_width = sprwidth;
+	_G(objs)[aa].last_height = sprheight;
 
 	tint_red = tint_green = tint_blue = tint_level = tint_light = light_level = 0;
 
-	if (objs[aa].flags & OBJF_HASTINT) {
+	if (_G(objs)[aa].flags & OBJF_HASTINT) {
 		// object specific tint, use it
-		tint_red = objs[aa].tint_r;
-		tint_green = objs[aa].tint_g;
-		tint_blue = objs[aa].tint_b;
-		tint_level = objs[aa].tint_level;
-		tint_light = objs[aa].tint_light;
+		tint_red = _G(objs)[aa].tint_r;
+		tint_green = _G(objs)[aa].tint_g;
+		tint_blue = _G(objs)[aa].tint_b;
+		tint_level = _G(objs)[aa].tint_level;
+		tint_light = _G(objs)[aa].tint_light;
 		light_level = 0;
-	} else if (objs[aa].flags & OBJF_HASLIGHT) {
-		light_level = objs[aa].tint_light;
+	} else if (_G(objs)[aa].flags & OBJF_HASLIGHT) {
+		light_level = _G(objs)[aa].tint_light;
 	} else {
 		// get the ambient or region tint
 		int ignoreRegionTints = 1;
-		if (objs[aa].flags & OBJF_USEREGIONTINTS)
+		if (_G(objs)[aa].flags & OBJF_USEREGIONTINTS)
 			ignoreRegionTints = 0;
 
-		get_local_tint(objs[aa].x, objs[aa].y, ignoreRegionTints,
+		get_local_tint(_G(objs)[aa].x, _G(objs)[aa].y, ignoreRegionTints,
 		               &tint_level, &tint_red, &tint_green, &tint_blue,
 		               &tint_light, &light_level);
 	}
 
 	// check whether the image should be flipped
 	int isMirrored = 0;
-	if ((objs[aa].view >= 0) &&
-	        (_G(views)[objs[aa].view].loops[objs[aa].loop].frames[objs[aa].frame].pic == objs[aa].num) &&
-	        ((_G(views)[objs[aa].view].loops[objs[aa].loop].frames[objs[aa].frame].flags & VFLG_FLIPSPRITE) != 0)) {
+	if ((_G(objs)[aa].view >= 0) &&
+	        (_G(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].pic == _G(objs)[aa].num) &&
+	        ((_G(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].flags & VFLG_FLIPSPRITE) != 0)) {
 		isMirrored = 1;
 	}
 
 	if ((hardwareAccelerated) &&
 	        (walkBehindMethod != DrawOverCharSprite) &&
 	        (_G(objcache)[aa].image != nullptr) &&
-	        (_G(objcache)[aa].sppic == objs[aa].num) &&
+	        (_G(objcache)[aa].sppic == _G(objs)[aa].num) &&
 	        (actsps[useindx] != nullptr)) {
 		// HW acceleration
 		_G(objcache)[aa].tintamntwas = tint_level;
@@ -1382,7 +1376,7 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 
 	// If we have the image cached, use it
 	if ((_G(objcache)[aa].image != nullptr) &&
-	        (_G(objcache)[aa].sppic == objs[aa].num) &&
+	        (_G(objcache)[aa].sppic == _G(objs)[aa].num) &&
 	        (_G(objcache)[aa].tintamntwas == tint_level) &&
 	        (_G(objcache)[aa].tintlightwas == tint_light) &&
 	        (_G(objcache)[aa].tintredwas == tint_red) &&
@@ -1397,8 +1391,8 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 			return 1;
 		// Check if the X & Y co-ords are the same, too -- if so, there
 		// is scope for further optimisations
-		if ((_G(objcache)[aa].xwas == objs[aa].x) &&
-		        (_G(objcache)[aa].ywas == objs[aa].y) &&
+		if ((_G(objcache)[aa].xwas == _G(objs)[aa].x) &&
+		        (_G(objcache)[aa].ywas == _G(objs)[aa].y) &&
 		        (actsps[useindx] != nullptr) &&
 		        (walk_behind_baselines_changed == 0))
 			return 1;
@@ -1413,16 +1407,16 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 	if (!hardwareAccelerated) {
 		// draw the base sprite, scaled and flipped as appropriate
 		actspsUsed = scale_and_flip_sprite(useindx, coldept, zoom_level,
-		                                   objs[aa].num, sprwidth, sprheight, isMirrored);
+		                                   _G(objs)[aa].num, sprwidth, sprheight, isMirrored);
 	} else {
 		// ensure actsps exists
-		actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, _GP(game).SpriteInfos[objs[aa].num].Width, _GP(game).SpriteInfos[objs[aa].num].Height);
+		actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, _GP(game).SpriteInfos[_G(objs)[aa].num].Width, _GP(game).SpriteInfos[_G(objs)[aa].num].Height);
 	}
 
 	// direct read from source bitmap, where possible
 	Bitmap *comeFrom = nullptr;
 	if (!actspsUsed)
-		comeFrom = _GP(spriteset)[objs[aa].num];
+		comeFrom = _GP(spriteset)[_G(objs)[aa].num];
 
 	// apply tints or lightenings where appropriate, else just copy
 	// the source bitmap
@@ -1431,14 +1425,14 @@ 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(_GP(spriteset)[objs[aa].num], 0, 0, 0, 0, _GP(game).SpriteInfos[objs[aa].num].Width, _GP(game).SpriteInfos[objs[aa].num].Height);
+		actsps[useindx]->Blit(_GP(spriteset)[_G(objs)[aa].num], 0, 0, 0, 0, _GP(game).SpriteInfos[_G(objs)[aa].num].Width, _GP(game).SpriteInfos[_G(objs)[aa].num].Height);
 	}
 
 	// Re-use the bitmap if it's the same size
 	_G(objcache)[aa].image = recycle_bitmap(_G(objcache)[aa].image, coldept, sprwidth, sprheight);
 	// Create the cached image and store it
 	_G(objcache)[aa].image->Blit(actsps[useindx], 0, 0, 0, 0, sprwidth, sprheight);
-	_G(objcache)[aa].sppic = objs[aa].num;
+	_G(objcache)[aa].sppic = _G(objs)[aa].num;
 	_G(objcache)[aa].tintamntwas = tint_level;
 	_G(objcache)[aa].tintredwas = tint_red;
 	_G(objcache)[aa].tintgrnwas = tint_green;
@@ -1456,12 +1450,12 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
 // This is only called from draw_screen_background, but it's seperated
 // to help with profiling the program
 void prepare_objects_for_drawing() {
-	our_eip = 32;
+	_G(our_eip) = 32;
 
-	for (int aa = 0; aa < croom->numobj; aa++) {
-		if (objs[aa].on != 1) continue;
+	for (int aa = 0; aa < _G(croom)->numobj; aa++) {
+		if (_G(objs)[aa].on != 1) continue;
 		// offscreen, don't draw
-		if ((objs[aa].x >= _GP(thisroom).Width) || (objs[aa].y < 1))
+		if ((_G(objs)[aa].x >= _GP(thisroom).Width) || (_G(objs)[aa].y < 1))
 			continue;
 
 		const int useindx = aa;
@@ -1469,26 +1463,26 @@ void prepare_objects_for_drawing() {
 		int actspsIntact = construct_object_gfx(aa, nullptr, &tehHeight, false);
 
 		// update the cache for next time
-		_G(objcache)[aa].xwas = objs[aa].x;
-		_G(objcache)[aa].ywas = objs[aa].y;
-		int atxp = data_to_game_coord(objs[aa].x);
-		int atyp = data_to_game_coord(objs[aa].y) - tehHeight;
+		_G(objcache)[aa].xwas = _G(objs)[aa].x;
+		_G(objcache)[aa].ywas = _G(objs)[aa].y;
+		int atxp = data_to_game_coord(_G(objs)[aa].x);
+		int atyp = data_to_game_coord(_G(objs)[aa].y) - tehHeight;
 
-		int usebasel = objs[aa].get_baseline();
+		int usebasel = _G(objs)[aa].get_baseline();
 
-		if (objs[aa].flags & OBJF_NOWALKBEHINDS) {
+		if (_G(objs)[aa].flags & OBJF_NOWALKBEHINDS) {
 			// ignore walk-behinds, do nothing
 			if (walkBehindMethod == DrawAsSeparateSprite) {
 				usebasel += _GP(thisroom).Height;
 			}
 		} else if (walkBehindMethod == DrawAsSeparateCharSprite) {
-			sort_out_char_sprite_walk_behind(useindx, atxp, atyp, usebasel, objs[aa].zoom, objs[aa].last_width, objs[aa].last_height);
+			sort_out_char_sprite_walk_behind(useindx, atxp, atyp, usebasel, _G(objs)[aa].zoom, _G(objs)[aa].last_width, _G(objs)[aa].last_height);
 		} else if ((!actspsIntact) && (walkBehindMethod == DrawOverCharSprite)) {
 			sort_out_walk_behinds(actsps[useindx], atxp, atyp, usebasel);
 		}
 
 		if ((!actspsIntact) || (actspsbmp[useindx] == nullptr)) {
-			bool hasAlpha = (_GP(game).SpriteInfos[objs[aa].num].Flags & SPF_ALPHACHANNEL) != 0;
+			bool hasAlpha = (_GP(game).SpriteInfos[_G(objs)[aa].num].Flags & SPF_ALPHACHANNEL) != 0;
 
 			if (actspsbmp[useindx] != nullptr)
 				gfxDriver->DestroyDDB(actspsbmp[useindx]);
@@ -1497,7 +1491,7 @@ void prepare_objects_for_drawing() {
 
 		if (gfxDriver->HasAcceleratedTransform()) {
 			actspsbmp[useindx]->SetFlippedLeftRight(_G(objcache)[aa].mirroredWas != 0);
-			actspsbmp[useindx]->SetStretch(objs[aa].last_width, objs[aa].last_height);
+			actspsbmp[useindx]->SetStretch(_G(objs)[aa].last_width, _G(objs)[aa].last_height);
 			actspsbmp[useindx]->SetTint(_G(objcache)[aa].tintredwas, _G(objcache)[aa].tintgrnwas, _G(objcache)[aa].tintbluwas, (_G(objcache)[aa].tintamntwas * 256) / 100);
 
 			if (_G(objcache)[aa].tintamntwas > 0) {
@@ -1513,7 +1507,7 @@ void prepare_objects_for_drawing() {
 				actspsbmp[useindx]->SetLightLevel(0);
 		}
 
-		add_to_sprite_list(actspsbmp[useindx], atxp, atyp, usebasel, objs[aa].transparent, objs[aa].num);
+		add_to_sprite_list(actspsbmp[useindx], atxp, atyp, usebasel, _G(objs)[aa].transparent, _G(objs)[aa].num);
 	}
 }
 
@@ -1570,21 +1564,21 @@ void prepare_characters_for_drawing() {
 	int light_level, coldept;
 	int tint_red, tint_green, tint_blue, tint_amount, tint_light = 255;
 
-	our_eip = 33;
+	_G(our_eip) = 33;
 
 	// draw characters
 	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;
+		if (_GP(game).chars[aa].room != _G(displayed_room)) continue;
 		eip_guinum = aa;
 		const int useindx = aa + MAX_ROOM_OBJECTS;
 
 		CharacterInfo *chin = &_GP(game).chars[aa];
-		our_eip = 330;
+		_G(our_eip) = 330;
 		// if it's on but set to view -1, they're being silly
 		if (chin->view < 0) {
 			quitprintf("!The character '%s' was turned on in the current room (room %d) but has not been assigned a view number.",
-			           chin->name, displayed_room);
+			           chin->name, _G(displayed_room));
 		}
 
 		if (chin->frame >= _G(views)[chin->view].loops[chin->loop].numFrames)
@@ -1599,10 +1593,10 @@ void prepare_characters_for_drawing() {
 		sppic = _G(views)[chin->view].loops[chin->loop].frames[chin->frame].pic;
 		if (sppic < 0)
 			sppic = 0;  // in case it's screwed up somehow
-		our_eip = 331;
+		_G(our_eip) = 331;
 		// sort out the stretching if required
 		onarea = get_walkable_area_at_character(aa);
-		our_eip = 332;
+		_G(our_eip) = 332;
 
 		// calculate the zoom level
 		if (chin->flags & CHF_MANUALSCALING)  // character ignores scaling
@@ -1635,7 +1629,7 @@ void prepare_characters_for_drawing() {
 			               &tint_light, &light_level);
 		}
 
-		our_eip = 3330;
+		_G(our_eip) = 3330;
 		int isMirrored = 0, specialpic = sppic;
 		bool usingCachedImage = false;
 
@@ -1648,7 +1642,7 @@ void prepare_characters_for_drawing() {
 			specialpic = -sppic;
 		}
 
-		our_eip = 3331;
+		_G(our_eip) = 3331;
 
 		// if the character was the same sprite and scaling last time,
 		// just use the cached image
@@ -1676,7 +1670,7 @@ void prepare_characters_for_drawing() {
 			_G(charcache)[aa].inUse = 0;
 		}
 
-		our_eip = 3332;
+		_G(our_eip) = 3332;
 
 		if (zoom_level != 100) {
 			// it needs to be stretched, so calculate the new dimensions
@@ -1693,7 +1687,7 @@ void prepare_characters_for_drawing() {
 			newheight = _GP(game).SpriteInfos[sppic].Height;
 		}
 
-		our_eip = 3336;
+		_G(our_eip) = 3336;
 
 		// Calculate the X & Y co-ordinates of where the sprite will be
 		const int atxp = (data_to_game_coord(chin->x)) - newwidth / 2;
@@ -1725,7 +1719,7 @@ void prepare_characters_for_drawing() {
 				actsps[useindx] = recycle_bitmap(actsps[useindx], coldept, _GP(game).SpriteInfos[sppic].Width, _GP(game).SpriteInfos[sppic].Height);
 			}
 
-			our_eip = 335;
+			_G(our_eip) = 335;
 
 			if (((light_level != 0) || (tint_amount != 0)) &&
 			        (!gfxDriver->HasAcceleratedTransform())) {
@@ -1753,7 +1747,7 @@ void prepare_characters_for_drawing() {
 
 		int usebasel = chin->get_baseline();
 
-		our_eip = 336;
+		_G(our_eip) = 336;
 
 		const int bgX = atxp + chin->pic_xoffs;
 		const int bgY = atyp + chin->pic_yoffs;
@@ -1794,7 +1788,7 @@ void prepare_characters_for_drawing() {
 
 		}
 
-		our_eip = 337;
+		_G(our_eip) = 337;
 
 		chin->actx = atxp;
 		chin->acty = atyp;
@@ -1833,11 +1827,11 @@ void prepare_room_sprites() {
 		prepare_characters_for_drawing();
 
 		if ((_G(debug_flags) & DBG_NODRAWSPRITES) == 0) {
-			our_eip = 34;
+			_G(our_eip) = 34;
 			draw_sprite_list();
 		}
 	}
-	our_eip = 36;
+	_G(our_eip) = 36;
 }
 
 // Draws the black surface behind (or rather between) the room viewports
@@ -1855,7 +1849,7 @@ void draw_preroom_background() {
 // no_transform flag tells to copy dirty regions on roomcam_surface without any coordinate conversion
 // whatsoever.
 PBitmap draw_room_background(Viewport *view, const SpriteTransform &room_trans) {
-	our_eip = 31;
+	_G(our_eip) = 31;
 
 	// For the sake of software renderer, if there is any kind of camera transform required
 	// except screen offset, we tell it to draw on separate bitmap first with zero transformation.
@@ -1903,7 +1897,7 @@ void draw_fps(const Rect &viewport) {
 
 	char base_buffer[20];
 	if (!isTimerFpsMaxed()) {
-		sprintf(base_buffer, "%d", frames_per_second);
+		sprintf(base_buffer, "%d", _G(frames_per_second));
 	} else {
 		sprintf(base_buffer, "unlimited");
 	}
@@ -1949,8 +1943,8 @@ void draw_gui_and_overlays() {
 
 	// Draw GUIs - they should always be on top of overlays like
 	// speech background text
-	our_eip = 35;
-	if (((_G(debug_flags) & DBG_NOIFACE) == 0) && (displayed_room >= 0)) {
+	_G(our_eip) = 35;
+	if (((_G(debug_flags) & DBG_NOIFACE) == 0) && (_G(displayed_room) >= 0)) {
 		int aa;
 
 		if (playerchar->activeinv >= MAX_INV) {
@@ -1959,7 +1953,7 @@ void draw_gui_and_overlays() {
 		}
 		if (playerchar->activeinv < 1) gui_inv_pic = -1;
 		else gui_inv_pic = _GP(game).invinfo[playerchar->activeinv].pic;
-		our_eip = 37;
+		_G(our_eip) = 37;
 		if (guis_need_update) {
 			guis_need_update = 0;
 			for (aa = 0; aa < _GP(game).numgui; aa++) {
@@ -1969,11 +1963,11 @@ void draw_gui_and_overlays() {
 					recreate_guibg_image(&_GP(guis)[aa]);
 
 				eip_guinum = aa;
-				our_eip = 370;
+				_G(our_eip) = 370;
 				guibg[aa]->ClearTransparent();
-				our_eip = 372;
+				_G(our_eip) = 372;
 				_GP(guis)[aa].DrawAt(guibg[aa], 0, 0);
-				our_eip = 373;
+				_G(our_eip) = 373;
 
 				bool isAlpha = false;
 				if (_GP(guis)[aa].HasAlphaChannel()) {
@@ -1990,10 +1984,10 @@ void draw_gui_and_overlays() {
 				} else {
 					guibgbmp[aa] = gfxDriver->CreateDDBFromBitmap(guibg[aa], isAlpha);
 				}
-				our_eip = 374;
+				_G(our_eip) = 374;
 			}
 		}
-		our_eip = 38;
+		_G(our_eip) = 38;
 		// Draw the GUIs
 		for (int gg = 0; gg < _GP(game).numgui; gg++) {
 			aa = _GP(play).gui_draw_order[gg];
@@ -2023,7 +2017,7 @@ void draw_gui_and_overlays() {
 		}
 	}
 
-	our_eip = 1099;
+	_G(our_eip) = 1099;
 }
 
 // Push the gathered list of sprites into the active graphic renderer
@@ -2056,11 +2050,11 @@ void put_sprite_list_on_screen(bool in_room) {
 			quit("Unknown entry in draw list");
 	}
 
-	our_eip = 1100;
+	_G(our_eip) = 1100;
 }
 
 bool GfxDriverNullSpriteCallback(int x, int y) {
-	if (displayed_room < 0) {
+	if (_G(displayed_room) < 0) {
 		// if no room loaded, various stuff won't be initialized yet
 		return 1;
 	}
@@ -2132,7 +2126,7 @@ void construct_game_scene(bool full_redraw) {
 	if (_GP(play).fast_forward)
 		return;
 
-	our_eip = 3;
+	_G(our_eip) = 3;
 
 	// React to changes to viewports and cameras (possibly from script) just before the render
 	_GP(play).UpdateViewports();
@@ -2148,12 +2142,12 @@ void construct_game_scene(bool full_redraw) {
 
 	// TODO: move to game update! don't call update during rendering pass!
 	// IMPORTANT: keep the order same because sometimes script may depend on it
-	if (displayed_room >= 0)
+	if (_G(displayed_room) >= 0)
 		_GP(play).UpdateRoomCameras();
 
 	// Stage: room viewports
 	if (_GP(play).screen_is_faded_out == 0 && _G(is_complete_overlay) == 0) {
-		if (displayed_room >= 0) {
+		if (_G(displayed_room) >= 0) {
 			construct_room_view();
 		} else if (!gfxDriver->RequiresFullRedrawEachFrame()) {
 			// black it out so we don't get cursor trails
@@ -2162,7 +2156,7 @@ void construct_game_scene(bool full_redraw) {
 		}
 	}
 
-	our_eip = 4;
+	_G(our_eip) = 4;
 
 	// Stage: UI overlay
 	if (_GP(play).screen_is_faded_out == 0) {
@@ -2283,14 +2277,14 @@ 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) & (_GP(game).color_depth > 1))
+	if ((_G(in_new_room) > 0) & (_GP(game).color_depth > 1))
 		return;
 
 	// TODO: find out if it's okay to move shake to update function
 	update_shakescreen();
 
 	construct_game_scene(false);
-	our_eip = 5;
+	_G(our_eip) = 5;
 	// NOTE: extraBitmap will always be drawn with the UI render stage
 	if (extraBitmap != nullptr) {
 		invalidate_sprite(extraX, extraY, extraBitmap, false);
diff --git a/engines/ags/engine/ac/drawingsurface.cpp b/engines/ags/engine/ac/drawingsurface.cpp
index d0e99dfa32..774182ac55 100644
--- a/engines/ags/engine/ac/drawingsurface.cpp
+++ b/engines/ags/engine/ac/drawingsurface.cpp
@@ -52,13 +52,6 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-
-
-extern RoomStatus *croom;
-extern RoomObject *objs;
-
-
-
 extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
 
 // ** SCRIPT DRAWINGSURFACE OBJECT
@@ -85,9 +78,9 @@ void DrawingSurface_Release(ScriptDrawingSurface *sds) {
 		if (sds->modified) {
 			int tt;
 			// force a refresh of any cached object or character images
-			if (croom != nullptr) {
-				for (tt = 0; tt < croom->numobj; tt++) {
-					if (objs[tt].num == sds->dynamicSpriteNumber)
+			if (_G(croom) != nullptr) {
+				for (tt = 0; tt < _G(croom)->numobj; tt++) {
+					if (_G(objs)[tt].num == sds->dynamicSpriteNumber)
 						_G(objcache)[tt].sppic = -31999;
 				}
 			}
diff --git a/engines/ags/engine/ac/dynamicsprite.cpp b/engines/ags/engine/ac/dynamicsprite.cpp
index f200de2451..76f48da8ce 100644
--- a/engines/ags/engine/ac/dynamicsprite.cpp
+++ b/engines/ags/engine/ac/dynamicsprite.cpp
@@ -49,14 +49,6 @@ namespace AGS3 {
 using namespace Shared;
 using namespace Engine;
 
-
-
-
-extern RoomObject *objs;
-extern RoomStatus *croom;
-
-
-
 extern color palette[256];
 extern AGS::Engine::IGraphicsDriver *gfxDriver;
 
@@ -490,10 +482,10 @@ void free_dynamic_sprite(int gotSlot) {
 	}
 
 	// force refresh of any object caches using the sprite
-	if (croom != nullptr) {
-		for (tt = 0; tt < croom->numobj; tt++) {
-			if (objs[tt].num == gotSlot) {
-				objs[tt].num = 0;
+	if (_G(croom) != nullptr) {
+		for (tt = 0; tt < _G(croom)->numobj; tt++) {
+			if (_G(objs)[tt].num == gotSlot) {
+				_G(objs)[tt].num = 0;
 				_G(objcache)[tt].sppic = -1;
 			} else if (_G(objcache)[tt].sppic == gotSlot)
 				_G(objcache)[tt].sppic = -1;
diff --git a/engines/ags/engine/ac/event.cpp b/engines/ags/engine/ac/event.cpp
index 23361b01c3..d87a809a64 100644
--- a/engines/ags/engine/ac/event.cpp
+++ b/engines/ags/engine/ac/event.cpp
@@ -49,13 +49,9 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 
-
-extern RoomStatus *croom;
-extern int displayed_room;
-
 extern color palette[256];
 extern IGraphicsDriver *gfxDriver;
-extern AGSPlatformDriver *platform;
+
 extern color old_palette[256];
 
 int in_enters_screen = 0, done_es_error = 0;
@@ -118,7 +114,7 @@ void run_room_event(int id) {
 	if (_GP(thisroom).EventHandlers != nullptr) {
 		run_interaction_script(_GP(thisroom).EventHandlers.get(), id);
 	} else {
-		run_interaction_event(&croom->intrRoom, id);
+		run_interaction_event(&_G(croom)->intrRoom, id);
 	}
 }
 
@@ -175,7 +171,7 @@ void process_event(EventHappened *evp) {
 			if (_GP(thisroom).Hotspots[evp->data2].EventHandlers != nullptr)
 				scriptPtr = _GP(thisroom).Hotspots[evp->data2].EventHandlers;
 			else
-				evpt = &croom->intrHotspot[evp->data2];
+				evpt = &_G(croom)->intrHotspot[evp->data2];
 
 			evblockbasename = "hotspot%d";
 			evblocknum = evp->data2;
@@ -185,12 +181,12 @@ void process_event(EventHappened *evp) {
 			if (_GP(thisroom).EventHandlers != nullptr)
 				scriptPtr = _GP(thisroom).EventHandlers;
 			else
-				evpt = &croom->intrRoom;
+				evpt = &_G(croom)->intrRoom;
 
 			evblockbasename = "room";
 			if (evp->data3 == 5) {
 				in_enters_screen++;
-				run_on_event(GE_ENTER_ROOM, RuntimeScriptValue().SetInt32(displayed_room));
+				run_on_event(GE_ENTER_ROOM, RuntimeScriptValue().SetInt32(_G(displayed_room)));
 
 			}
 			//Debug::Printf("Running room interaction, event %d", evp->data3);
diff --git a/engines/ags/engine/ac/file.cpp b/engines/ags/engine/ac/file.cpp
index ecdcc0322c..1152e7ca47 100644
--- a/engines/ags/engine/ac/file.cpp
+++ b/engines/ags/engine/ac/file.cpp
@@ -55,7 +55,7 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern AGSPlatformDriver *platform;
+
 extern int MAXSTRLEN;
 
 // object-based File routines
@@ -210,7 +210,7 @@ const char *GameSavedgamesDirToken = "$SAVEGAMEDIR$";
 const char *GameDataDirToken = "$APPDATADIR$";
 
 void FixupFilename(char *filename) {
-	const char *illegal = platform->GetIllegalFileChars();
+	const char *illegal = _G(platform)->GetIllegalFileChars();
 	for (char *name_ptr = filename; *name_ptr; ++name_ptr) {
 		if (*name_ptr < ' ') {
 			*name_ptr = '_';
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index f640febca9..09b7a01fe9 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -144,21 +144,7 @@ extern IGraphicsDriver *gfxDriver;
 
 //=============================================================================
 
-RoomObject *objs;
-RoomStatus *croom = nullptr;
-
-volatile int switching_away_from_game = 0;
-volatile bool switched_away = false;
 GameDataVersion loaded_game_file_version = kGameVersion_Undefined;
-int frames_per_second = 40;
-int displayed_room = -10, starting_room = -1;
-int in_new_room = 0, new_room_was = 0; // 1 in new room, 2 first time in new room, 3 loading saved game
-int new_room_pos = 0;
-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
-int proper_exit = 0, our_eip = 0;
 
 //=============================================================================
 
@@ -272,7 +258,7 @@ void set_debug_mode(bool on) {
 }
 
 void set_game_speed(int new_fps) {
-	frames_per_second = new_fps;
+	_G(frames_per_second) = new_fps;
 	if (!isTimerFpsMaxed()) // if in maxed mode, don't update timer for now
 		setTimerFps(new_fps);
 }
@@ -336,7 +322,7 @@ bool MakeSaveGameDir(const String &newFolder, ResolvedPath &rp) {
 
 	if (newSaveGameDir.CompareLeft(UserSavedgamesRootToken, strlen(UserSavedgamesRootToken)) == 0) {
 		if (_G(saveGameParent).IsEmpty()) {
-			base_dir = PathOrCurDir(platform->GetUserSavedgamesDirectory());
+			base_dir = PathOrCurDir(_G(platform)->GetUserSavedgamesDirectory());
 			newSaveGameDir.ReplaceMid(0, strlen(UserSavedgamesRootToken), base_dir);
 		} else {
 			// If there is a custom save parent directory, then replace
@@ -351,7 +337,7 @@ bool MakeSaveGameDir(const String &newFolder, ResolvedPath &rp) {
 		// Convert the path relative to installation folder into path relative to the
 		// safe save path with default name
 		if (_G(saveGameParent).IsEmpty()) {
-			base_dir = PathOrCurDir(platform->GetUserSavedgamesDirectory());
+			base_dir = PathOrCurDir(_G(platform)->GetUserSavedgamesDirectory());
 			newSaveGameDir.Format("%s/%s/%s", base_dir.GetCStr(), _GP(game).saveGameFolderName, newFolder.GetCStr());
 		} else {
 			base_dir = _G(saveGameParent);
@@ -999,7 +985,7 @@ void save_game(int slotn, const char *descript) {
 		return;
 	}
 
-	if (platform->GetDiskFreeSpaceMB() < 2) {
+	if (_G(platform)->GetDiskFreeSpaceMB() < 2) {
 		Display("ERROR: There is not enough disk space free to save the game. Clear some disk space and try again.");
 		return;
 	}
@@ -1094,7 +1080,7 @@ void ReadRoomStatus_Aligned(RoomStatus *roomstat, Stream *in) {
 void restore_game_room_state(Stream *in) {
 	int vv;
 
-	displayed_room = in->ReadInt32();
+	_G(displayed_room) = in->ReadInt32();
 
 	// read the room state for all the rooms the player has been in
 	RoomStatus *roomstat;
@@ -1277,7 +1263,7 @@ void restore_game_displayed_room_status(Stream *in, RestoredData &r_data) {
 	for (bb = 0; bb < MAX_ROOM_BGFRAMES; bb++)
 		r_data.RoomBkgScene[bb].reset();
 
-	if (displayed_room >= 0) {
+	if (_G(displayed_room) >= 0) {
 
 		for (bb = 0; bb < MAX_ROOM_BGFRAMES; bb++) {
 			r_data.RoomBkgScene[bb] = nullptr;
@@ -1510,8 +1496,8 @@ HSaveError load_game(int slotNumber, bool &data_overwritten) {
 	data_overwritten = false;
 	gameHasBeenRestored++;
 
-	oldeip = our_eip;
-	our_eip = 2050;
+	oldeip = _G(our_eip);
+	_G(our_eip) = 2050;
 
 	HSaveError err;
 	SavegameSource src;
@@ -1548,7 +1534,7 @@ HSaveError load_game(int slotNumber, bool &data_overwritten) {
 	if (!err)
 		return err;
 	src.InputStream.reset();
-	our_eip = oldeip;
+	_G(our_eip) = oldeip;
 
 	// ensure keyboard buffer is clean
 	ags_clear_input_buffer();
@@ -1675,11 +1661,11 @@ int __GetLocationType(int xxx, int yyy, int allowHotspot0) {
 	int wbat = _GP(thisroom).WalkBehindMask->GetPixel(xxx, yyy);
 
 	if (wbat <= 0) wbat = 0;
-	else wbat = croom->walkbehind_base[wbat];
+	else wbat = _G(croom)->walkbehind_base[wbat];
 
 	int winner = 0;
 	// if it's an Ignore Walkbehinds object, then ignore the walkbehind
-	if ((objat >= 0) && ((objs[objat].flags & OBJF_NOWALKBEHINDS) != 0))
+	if ((objat >= 0) && ((_G(objs)[objat].flags & OBJF_NOWALKBEHINDS) != 0))
 		wbat = 0;
 	if ((charat >= 0) && ((_GP(game).chars[charat].flags & CHF_NOWALKBEHINDS) != 0))
 		wbat = 0;
@@ -1723,12 +1709,12 @@ int __GetLocationType(int xxx, int yyy, int allowHotspot0) {
 
 // Called whenever game looses input focus
 void display_switch_out() {
-	switched_away = true;
+	_G(switched_away) = true;
 	ags_clear_input_buffer();
 	// Always unlock mouse when switching out from the game
 	Mouse::UnlockFromWindow();
-	platform->DisplaySwitchOut();
-	platform->ExitFullscreenMode();
+	_G(platform)->DisplaySwitchOut();
+	_G(platform)->ExitFullscreenMode();
 }
 
 void display_switch_out_suspend() {
@@ -1736,9 +1722,9 @@ void display_switch_out_suspend() {
 	//debug_script_warn("display_switch_out");
 	display_switch_out();
 
-	switching_away_from_game++;
+	_G(switching_away_from_game)++;
 
-	platform->PauseApplication();
+	_G(platform)->PauseApplication();
 
 	// allow background running temporarily to halt the sound
 	if (set_display_switch_mode(SWITCH_BACKGROUND) == -1)
@@ -1755,23 +1741,23 @@ void display_switch_out_suspend() {
 		}
 	} // -- AudioChannelsLock
 
-	platform->Delay(1000);
+	_G(platform)->Delay(1000);
 
 	// restore the callbacks
 	SetMultitasking(0);
 
-	switching_away_from_game--;
+	_G(switching_away_from_game)--;
 }
 
 // Called whenever game gets input focus
 void display_switch_in() {
-	switched_away = false;
+	_G(switched_away) = false;
 	if (gfxDriver) {
 		DisplayMode mode = gfxDriver->GetDisplayMode();
 		if (!mode.Windowed)
-			platform->EnterFullscreenMode(mode);
+			_G(platform)->EnterFullscreenMode(mode);
 	}
-	platform->DisplaySwitchIn();
+	_G(platform)->DisplaySwitchIn();
 	ags_clear_input_buffer();
 	// If auto lock option is set, lock mouse to the game window
 	if (_GP(usetup).mouse_auto_lock && _GP(scsystem).windowed)
@@ -1795,7 +1781,7 @@ void display_switch_in_resume() {
 	if (gfxDriver && gfxDriver->UsesMemoryBackBuffer())
 		gfxDriver->ClearRectangle(0, 0, _GP(game).GetGameRes().Width - 1, _GP(game).GetGameRes().Height - 1, nullptr);
 
-	platform->ResumeApplication();
+	_G(platform)->ResumeApplication();
 }
 
 void replace_tokens(const char *srcmes, char *destm, int maxlen) {
diff --git a/engines/ags/engine/ac/game.h b/engines/ags/engine/ac/game.h
index 1d8c84428e..975ae48c5d 100644
--- a/engines/ags/engine/ac/game.h
+++ b/engines/ags/engine/ac/game.h
@@ -196,11 +196,6 @@ void get_message_text(int msnum, char *buffer, char giveErr = 1);
 
 bool unserialize_audio_script_object(int index, const char *objectType, const char *serializedData, int dataSize);
 
-extern int in_new_room;
-extern int new_room_pos;
-extern int new_room_x, new_room_y, new_room_loop;
-extern int displayed_room;
-extern int frames_per_second; // fixed game fps, set by script
 extern unsigned int loopcounter;
 extern void set_loop_counter(unsigned int new_counter);
 extern int game_paused;
diff --git a/engines/ags/engine/ac/global_character.cpp b/engines/ags/engine/ac/global_character.cpp
index 643e5b7ad6..73e4ba7ae6 100644
--- a/engines/ags/engine/ac/global_character.cpp
+++ b/engines/ags/engine/ac/global_character.cpp
@@ -52,9 +52,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
-extern RoomObject *objs;
-
 // defined in character unit
 extern CharacterExtras *charextra;
 extern CharacterInfo *playerchar;
@@ -332,7 +329,7 @@ void MoveCharacterToObject(int chaa, int obbj) {
 	if (!is_valid_object(obbj))
 		return;
 
-	walk_character(chaa, objs[obbj].x + 5, objs[obbj].y + 6, 0, true);
+	walk_character(chaa, _G(objs)[obbj].x + 5, _G(objs)[obbj].y + 6, 0, true);
 
 	GameLoopUntilNotMoving(&_GP(game).chars[chaa].walking);
 }
diff --git a/engines/ags/engine/ac/global_debug.cpp b/engines/ags/engine/ac/global_debug.cpp
index c72607a30c..d031ee70ec 100644
--- a/engines/ags/engine/ac/global_debug.cpp
+++ b/engines/ags/engine/ac/global_debug.cpp
@@ -57,7 +57,6 @@ extern CharacterInfo *playerchar;
 extern int convert_16bit_bgr;
 extern IGraphicsDriver *gfxDriver;
 extern TreeMap *transtree;
-extern int displayed_room, starting_room;
 extern char transFileName[MAX_PATH];
 
 String GetRuntimeInfo() {
@@ -126,13 +125,13 @@ void script_debug(int cmdd, int dataa) {
 		int goToRoom = -1;
 		if (_GP(game).roomCount == 0) {
 			char inroomtex[80];
-			sprintf(inroomtex, "!Enter new room: (in room %d)", displayed_room);
+			sprintf(inroomtex, "!Enter new room: (in room %d)", _G(displayed_room));
 			setup_for_dialog();
 			goToRoom = enternumberwindow(inroomtex);
 			restore_after_dialog();
 		} else {
 			setup_for_dialog();
-			goToRoom = roomSelectorWindow(displayed_room, _GP(game).roomCount, _GP(game).roomNumbers, _GP(game).roomNames);
+			goToRoom = roomSelectorWindow(_G(displayed_room), _GP(game).roomCount, _GP(game).roomNumbers, _GP(game).roomNames);
 			restore_after_dialog();
 		}
 		if (goToRoom >= 0)
diff --git a/engines/ags/engine/ac/global_game.cpp b/engines/ags/engine/ac/global_game.cpp
index fd98556805..934e993393 100644
--- a/engines/ags/engine/ac/global_game.cpp
+++ b/engines/ags/engine/ac/global_game.cpp
@@ -75,12 +75,11 @@ using namespace AGS::Shared;
 
 #define ALLEGRO_KEYBOARD_HANDLER
 
-extern int displayed_room;
+
 extern int game_paused;
 extern char gamefilenamebuf[200];
 extern unsigned int load_new_game;
 extern int load_new_game_restore;
-extern RoomStatus *croom;
 extern int gui_disabled_style;
 extern int getloctype_index;
 extern IGraphicsDriver *gfxDriver;
@@ -110,7 +109,7 @@ void restart_game() {
 }
 
 void RestoreGameSlot(int slnum) {
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		quit("!RestoreGameSlot: a game cannot be restored from within game_start");
 
 	can_run_delayed_command();
@@ -261,7 +260,7 @@ int RunAGSGame(const char *newgame, unsigned int mode, int data) {
 	int ee;
 
 	unload_old_room();
-	displayed_room = -10;
+	_G(displayed_room) = -10;
 
 	save_config_file(); // save current user config in case engine fails to run new game
 	unload_game_file();
@@ -345,7 +344,7 @@ int GetGameParameter(int parm, int data1, int data2, int data3) {
 	case GP_NUMGUIS:
 		return _GP(game).numgui;
 	case GP_NUMOBJECTS:
-		return croom->numobj;
+		return _G(croom)->numobj;
 	case GP_NUMCHARACTERS:
 		return _GP(game).numcharacters;
 	case GP_NUMINVITEMS:
@@ -432,7 +431,7 @@ int GetGameOption(int opt) {
 void SkipUntilCharacterStops(int cc) {
 	if (!is_valid_character(cc))
 		quit("!SkipUntilCharacterStops: invalid character specified");
-	if (_GP(game).chars[cc].room != displayed_room)
+	if (_GP(game).chars[cc].room != _G(displayed_room))
 		quit("!SkipUntilCharacterStops: specified character not in current room");
 
 	// if they are not currently moving, do nothing
@@ -524,7 +523,7 @@ void SaveCursorForLocationChange() {
 }
 
 void GetLocationName(int xxx, int yyy, char *tempo) {
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		quit("!GetLocationName: no room has been loaded");
 
 	VALIDATE_STRING(tempo);
@@ -665,57 +664,57 @@ int IsKeyPressed(int keycode) {
 		return ags_iskeypressed(__allegro_KEY_9);
 
 	case eAGSKeyCodeA:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('A'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('A'));
 	case eAGSKeyCodeB:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('B'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('B'));
 	case eAGSKeyCodeC:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('C'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('C'));
 	case eAGSKeyCodeD:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('D'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('D'));
 	case eAGSKeyCodeE:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('E'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('E'));
 	case eAGSKeyCodeF:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('F'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('F'));
 	case eAGSKeyCodeG:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('G'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('G'));
 	case eAGSKeyCodeH:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('H'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('H'));
 	case eAGSKeyCodeI:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('I'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('I'));
 	case eAGSKeyCodeJ:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('J'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('J'));
 	case eAGSKeyCodeK:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('K'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('K'));
 	case eAGSKeyCodeL:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('L'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('L'));
 	case eAGSKeyCodeM:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('M'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('M'));
 	case eAGSKeyCodeN:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('N'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('N'));
 	case eAGSKeyCodeO:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('O'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('O'));
 	case eAGSKeyCodeP:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('P'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('P'));
 	case eAGSKeyCodeQ:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('Q'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('Q'));
 	case eAGSKeyCodeR:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('R'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('R'));
 	case eAGSKeyCodeS:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('S'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('S'));
 	case eAGSKeyCodeT:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('T'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('T'));
 	case eAGSKeyCodeU:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('U'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('U'));
 	case eAGSKeyCodeV:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('V'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('V'));
 	case eAGSKeyCodeW:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('W'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('W'));
 	case eAGSKeyCodeX:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('X'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('X'));
 	case eAGSKeyCodeY:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('Y'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('Y'));
 	case eAGSKeyCodeZ:
-		return ags_iskeypressed(platform->ConvertKeycodeToScanCode('Z'));
+		return ags_iskeypressed(_G(platform)->ConvertKeycodeToScanCode('Z'));
 
 	case eAGSKeyCodeF1:
 		return ags_iskeypressed(__allegro_KEY_F1);
diff --git a/engines/ags/engine/ac/global_hotspot.cpp b/engines/ags/engine/ac/global_hotspot.cpp
index 69d96445bf..b8175233da 100644
--- a/engines/ags/engine/ac/global_hotspot.cpp
+++ b/engines/ags/engine/ac/global_hotspot.cpp
@@ -42,23 +42,19 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
-extern RoomStatus *croom;
 extern CharacterInfo *playerchar;
 
-
-
 void DisableHotspot(int hsnum) {
 	if ((hsnum < 1) | (hsnum >= MAX_ROOM_HOTSPOTS))
 		quit("!DisableHotspot: invalid hotspot specified");
-	croom->hotspot_enabled[hsnum] = 0;
+	_G(croom)->hotspot_enabled[hsnum] = 0;
 	debug_script_log("Hotspot %d disabled", hsnum);
 }
 
 void EnableHotspot(int hsnum) {
 	if ((hsnum < 1) | (hsnum >= MAX_ROOM_HOTSPOTS))
 		quit("!EnableHotspot: invalid hotspot specified");
-	croom->hotspot_enabled[hsnum] = 1;
+	_G(croom)->hotspot_enabled[hsnum] = 1;
 	debug_script_log("Hotspot %d re-enabled", hsnum);
 }
 
@@ -131,14 +127,14 @@ void RunHotspotInteraction(int hotspothere, int mood) {
 		run_interaction_script(_GP(thisroom).Hotspots[hotspothere].EventHandlers.get(), 5);  // any click on hotspot
 	} else {
 		if (passon >= 0) {
-			if (run_interaction_event(&croom->intrHotspot[hotspothere], passon, 5, (passon == 3))) {
+			if (run_interaction_event(&_G(croom)->intrHotspot[hotspothere], passon, 5, (passon == 3))) {
 				evblockbasename = oldbasename;
 				evblocknum = oldblocknum;
 				return;
 			}
 		}
 		// run the 'any click on hs' event
-		run_interaction_event(&croom->intrHotspot[hotspothere], 5);
+		run_interaction_event(&_G(croom)->intrHotspot[hotspothere], 5);
 	}
 
 	evblockbasename = oldbasename;
@@ -146,11 +142,11 @@ void RunHotspotInteraction(int hotspothere, int mood) {
 }
 
 int GetHotspotProperty(int hss, const char *property) {
-	return get_int_property(_GP(thisroom).Hotspots[hss].Properties, croom->hsProps[hss], property);
+	return get_int_property(_GP(thisroom).Hotspots[hss].Properties, _G(croom)->hsProps[hss], property);
 }
 
 void GetHotspotPropertyText(int item, const char *property, char *bufer) {
-	get_text_property(_GP(thisroom).Hotspots[item].Properties, croom->hsProps[item], property, bufer);
+	get_text_property(_GP(thisroom).Hotspots[item].Properties, _G(croom)->hsProps[item], property, bufer);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_object.cpp b/engines/ags/engine/ac/global_object.cpp
index 4d68ab6d7e..ea6a8a2923 100644
--- a/engines/ags/engine/ac/global_object.cpp
+++ b/engines/ags/engine/ac/global_object.cpp
@@ -52,14 +52,7 @@ using namespace AGS::Shared;
 
 #define OVERLAPPING_OBJECT 1000
 
-extern RoomStatus *croom;
-extern RoomObject *objs;
-
-
-
-
 extern CharacterInfo *playerchar;
-extern int displayed_room;
 
 extern int actSpsCount;
 extern Bitmap **actsps;
@@ -80,16 +73,16 @@ int GetObjectIDAtScreen(int scrx, int scry) {
 int GetObjectIDAtRoom(int roomx, int roomy) {
 	int aa, bestshotyp = -1, bestshotwas = -1;
 	// Iterate through all objects in the room
-	for (aa = 0; aa < croom->numobj; aa++) {
-		if (objs[aa].on != 1) continue;
-		if (objs[aa].flags & OBJF_NOINTERACT)
+	for (aa = 0; aa < _G(croom)->numobj; aa++) {
+		if (_G(objs)[aa].on != 1) continue;
+		if (_G(objs)[aa].flags & OBJF_NOINTERACT)
 			continue;
-		int xxx = objs[aa].x, yyy = objs[aa].y;
+		int xxx = _G(objs)[aa].x, yyy = _G(objs)[aa].y;
 		int isflipped = 0;
-		int spWidth = game_to_data_coord(objs[aa].get_width());
-		int spHeight = game_to_data_coord(objs[aa].get_height());
-		if (objs[aa].view >= 0)
-			isflipped = _G(views)[objs[aa].view].loops[objs[aa].loop].frames[objs[aa].frame].flags & VFLG_FLIPSPRITE;
+		int spWidth = game_to_data_coord(_G(objs)[aa].get_width());
+		int spHeight = game_to_data_coord(_G(objs)[aa].get_height());
+		if (_G(objs)[aa].view >= 0)
+			isflipped = _G(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].flags & VFLG_FLIPSPRITE;
 
 		Bitmap *theImage = GetObjectImage(aa, &isflipped);
 
@@ -97,7 +90,7 @@ int GetObjectIDAtRoom(int roomx, int roomy) {
 			spWidth, spHeight, isflipped) == FALSE)
 			continue;
 
-		int usebasel = objs[aa].get_baseline();
+		int usebasel = _G(objs)[aa].get_baseline();
 		if (usebasel < bestshotyp) continue;
 
 		bestshotwas = aa;
@@ -119,22 +112,22 @@ void SetObjectTint(int obj, int red, int green, int blue, int opacity, int lumin
 
 	debug_script_log("Set object %d tint RGB(%d,%d,%d) %d%%", obj, red, green, blue, opacity);
 
-	objs[obj].tint_r = red;
-	objs[obj].tint_g = green;
-	objs[obj].tint_b = blue;
-	objs[obj].tint_level = opacity;
-	objs[obj].tint_light = (luminance * 25) / 10;
-	objs[obj].flags &= ~OBJF_HASLIGHT;
-	objs[obj].flags |= OBJF_HASTINT;
+	_G(objs)[obj].tint_r = red;
+	_G(objs)[obj].tint_g = green;
+	_G(objs)[obj].tint_b = blue;
+	_G(objs)[obj].tint_level = opacity;
+	_G(objs)[obj].tint_light = (luminance * 25) / 10;
+	_G(objs)[obj].flags &= ~OBJF_HASLIGHT;
+	_G(objs)[obj].flags |= OBJF_HASTINT;
 }
 
 void RemoveObjectTint(int obj) {
 	if (!is_valid_object(obj))
 		quit("!RemoveObjectTint: invalid object");
 
-	if (objs[obj].flags & (OBJF_HASTINT | OBJF_HASLIGHT)) {
+	if (_G(objs)[obj].flags & (OBJF_HASTINT | OBJF_HASLIGHT)) {
 		debug_script_log("Un-tint object %d", obj);
-		objs[obj].flags &= ~(OBJF_HASTINT | OBJF_HASLIGHT);
+		_G(objs)[obj].flags &= ~(OBJF_HASTINT | OBJF_HASLIGHT);
 	} else {
 		debug_script_warn("RemoveObjectTint called but object was not tinted");
 	}
@@ -148,12 +141,12 @@ void SetObjectView(int obn, int vii) {
 	}
 	vii--;
 
-	objs[obn].view = vii;
-	objs[obn].frame = 0;
-	if (objs[obn].loop >= _G(views)[vii].numLoops)
-		objs[obn].loop = 0;
-	objs[obn].cycling = 0;
-	objs[obn].num = _G(views)[vii].loops[0].frames[0].pic;
+	_G(objs)[obn].view = vii;
+	_G(objs)[obn].frame = 0;
+	if (_G(objs)[obn].loop >= _G(views)[vii].numLoops)
+		_G(objs)[obn].loop = 0;
+	_G(objs)[obn].cycling = 0;
+	_G(objs)[obn].num = _G(views)[vii].loops[0].frames[0].pic;
 }
 
 void SetObjectFrame(int obn, int viw, int lop, int fra) {
@@ -175,12 +168,12 @@ void SetObjectFrame(int obn, int viw, int lop, int fra) {
 		if (_G(views)[viw].loops[lop].numFrames == 0)
 			quit("!SetObjectFrame: specified loop has no frames");
 	}
-	objs[obn].view = viw;
-	objs[obn].loop = lop;
-	objs[obn].frame = fra;
-	objs[obn].cycling = 0;
-	objs[obn].num = _G(views)[viw].loops[lop].frames[fra].pic;
-	CheckViewFrame(viw, objs[obn].loop, objs[obn].frame);
+	_G(objs)[obn].view = viw;
+	_G(objs)[obn].loop = lop;
+	_G(objs)[obn].frame = fra;
+	_G(objs)[obn].cycling = 0;
+	_G(objs)[obn].num = _G(views)[viw].loops[lop].frames[fra].pic;
+	CheckViewFrame(viw, _G(objs)[obn].loop, _G(objs)[obn].frame);
 }
 
 // pass trans=0 for fully solid, trans=100 for fully transparent
@@ -188,7 +181,7 @@ void SetObjectTransparency(int obn, int trans) {
 	if (!is_valid_object(obn)) quit("!SetObjectTransparent: invalid object number specified");
 	if ((trans < 0) || (trans > 100)) quit("!SetObjectTransparent: transparency value must be between 0 and 100");
 
-	objs[obn].transparent = GfxDef::Trans100ToLegacyTrans255(trans);
+	_G(objs)[obn].transparent = GfxDef::Trans100ToLegacyTrans255(trans);
 }
 
 
@@ -196,19 +189,19 @@ void SetObjectTransparency(int obn, int trans) {
 void SetObjectBaseline(int obn, int basel) {
 	if (!is_valid_object(obn)) quit("!SetObjectBaseline: invalid object number specified");
 	// baseline has changed, invalidate the cache
-	if (objs[obn].baseline != basel) {
+	if (_G(objs)[obn].baseline != basel) {
 		_G(objcache)[obn].ywas = -9999;
-		objs[obn].baseline = basel;
+		_G(objs)[obn].baseline = basel;
 	}
 }
 
 int GetObjectBaseline(int obn) {
 	if (!is_valid_object(obn)) quit("!GetObjectBaseline: invalid object number specified");
 
-	if (objs[obn].baseline < 1)
+	if (_G(objs)[obn].baseline < 1)
 		return 0;
 
-	return objs[obn].baseline;
+	return _G(objs)[obn].baseline;
 }
 
 void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, int blocking, int sframe) {
@@ -218,38 +211,38 @@ void AnimateObjectImpl(int obn, int loopn, int spdd, int rept, int direction, in
 	}
 	if (!is_valid_object(obn))
 		quit("!AnimateObject: invalid object number specified");
-	if (objs[obn].view < 0)
+	if (_G(objs)[obn].view < 0)
 		quit("!AnimateObject: object has not been assigned a view");
-	if (loopn < 0 || loopn >= _G(views)[objs[obn].view].numLoops)
+	if (loopn < 0 || loopn >= _G(views)[_G(objs)[obn].view].numLoops)
 		quit("!AnimateObject: invalid loop number specified");
-	if (sframe < 0 || sframe >= _G(views)[objs[obn].view].loops[loopn].numFrames)
+	if (sframe < 0 || sframe >= _G(views)[_G(objs)[obn].view].loops[loopn].numFrames)
 		quit("!AnimateObject: invalid starting frame number specified");
 	if ((direction < 0) || (direction > 1))
 		quit("!AnimateObjectEx: invalid direction");
 	if ((rept < 0) || (rept > 2))
 		quit("!AnimateObjectEx: invalid repeat value");
-	if (_G(views)[objs[obn].view].loops[loopn].numFrames < 1)
+	if (_G(views)[_G(objs)[obn].view].loops[loopn].numFrames < 1)
 		quit("!AnimateObject: no frames in the specified view loop");
 
-	debug_script_log("Obj %d start anim view %d loop %d, speed %d, repeat %d, frame %d", obn, objs[obn].view + 1, loopn, spdd, rept, sframe);
+	debug_script_log("Obj %d start anim view %d loop %d, speed %d, repeat %d, frame %d", obn, _G(objs)[obn].view + 1, loopn, spdd, rept, sframe);
 
-	objs[obn].cycling = rept + 1 + (direction * 10);
-	objs[obn].loop = loopn;
+	_G(objs)[obn].cycling = rept + 1 + (direction * 10);
+	_G(objs)[obn].loop = loopn;
 	// reverse animation starts at the *previous frame*
 	if (direction) {
 		sframe--;
 		if (sframe < 0)
-			sframe = _G(views)[objs[obn].view].loops[loopn].numFrames - (-sframe);
+			sframe = _G(views)[_G(objs)[obn].view].loops[loopn].numFrames - (-sframe);
 	}
-	objs[obn].frame = sframe;
+	_G(objs)[obn].frame = sframe;
 
-	objs[obn].overall_speed = spdd;
-	objs[obn].wait = spdd + _G(views)[objs[obn].view].loops[loopn].frames[objs[obn].frame].speed;
-	objs[obn].num = _G(views)[objs[obn].view].loops[loopn].frames[objs[obn].frame].pic;
-	CheckViewFrame(objs[obn].view, loopn, objs[obn].frame);
+	_G(objs)[obn].overall_speed = spdd;
+	_G(objs)[obn].wait = spdd + _G(views)[_G(objs)[obn].view].loops[loopn].frames[_G(objs)[obn].frame].speed;
+	_G(objs)[obn].num = _G(views)[_G(objs)[obn].view].loops[loopn].frames[_G(objs)[obn].frame].pic;
+	CheckViewFrame(_G(objs)[obn].view, loopn, _G(objs)[obn].frame);
 
 	if (blocking)
-		GameLoopUntilValueIsZero(&objs[obn].cycling);
+		GameLoopUntilValueIsZero(&_G(objs)[obn].cycling);
 }
 
 void AnimateObjectEx(int obn, int loopn, int spdd, int rept, int direction, int blocking) {
@@ -272,23 +265,23 @@ void MergeObject(int obn) {
 	if (bg_frame->GetColorDepth() != actsps[obn]->GetColorDepth())
 		quit("!MergeObject: unable to merge object due to color depth differences");
 
-	int xpos = data_to_game_coord(objs[obn].x);
-	int ypos = (data_to_game_coord(objs[obn].y) - theHeight);
+	int xpos = data_to_game_coord(_G(objs)[obn].x);
+	int ypos = (data_to_game_coord(_G(objs)[obn].y) - theHeight);
 
-	draw_sprite_support_alpha(bg_frame.get(), false, xpos, ypos, actsps[obn], (_GP(game).SpriteInfos[objs[obn].num].Flags & SPF_ALPHACHANNEL) != 0);
+	draw_sprite_support_alpha(bg_frame.get(), false, xpos, ypos, actsps[obn], (_GP(game).SpriteInfos[_G(objs)[obn].num].Flags & SPF_ALPHACHANNEL) != 0);
 	invalidate_screen();
 	mark_current_background_dirty();
 
 	//abuf = oldabuf;
 	// mark the sprite as merged
-	objs[obn].on = 2;
+	_G(objs)[obn].on = 2;
 	debug_script_log("Object %d merged into background", obn);
 }
 
 void StopObjectMoving(int objj) {
 	if (!is_valid_object(objj))
 		quit("!StopObjectMoving: invalid object number");
-	objs[objj].moving = 0;
+	_G(objs)[objj].moving = 0;
 
 	debug_script_log("Object %d stop moving", objj);
 }
@@ -296,8 +289,8 @@ void StopObjectMoving(int objj) {
 void ObjectOff(int obn) {
 	if (!is_valid_object(obn)) quit("!ObjectOff: invalid object specified");
 	// don't change it if on == 2 (merged)
-	if (objs[obn].on == 1) {
-		objs[obn].on = 0;
+	if (_G(objs)[obn].on == 1) {
+		_G(objs)[obn].on = 0;
 		debug_script_log("Object %d turned off", obn);
 		StopObjectMoving(obn);
 	}
@@ -305,8 +298,8 @@ void ObjectOff(int obn) {
 
 void ObjectOn(int obn) {
 	if (!is_valid_object(obn)) quit("!ObjectOn: invalid object specified");
-	if (objs[obn].on == 0) {
-		objs[obn].on = 1;
+	if (_G(objs)[obn].on == 0) {
+		_G(objs)[obn].on = 1;
 		debug_script_log("Object %d turned on", obn);
 	}
 }
@@ -315,7 +308,7 @@ int IsObjectOn(int objj) {
 	if (!is_valid_object(objj)) quit("!IsObjectOn: invalid object number");
 
 	// ==1 is on, ==2 is merged into background
-	if (objs[objj].on == 1)
+	if (_G(objs)[objj].on == 1)
 		return 1;
 
 	return 0;
@@ -324,47 +317,47 @@ int IsObjectOn(int objj) {
 void SetObjectGraphic(int obn, int slott) {
 	if (!is_valid_object(obn)) quit("!SetObjectGraphic: invalid object specified");
 
-	if (objs[obn].num != slott) {
-		objs[obn].num = slott;
+	if (_G(objs)[obn].num != slott) {
+		_G(objs)[obn].num = slott;
 		debug_script_log("Object %d graphic changed to slot %d", obn, slott);
 	}
-	objs[obn].cycling = 0;
-	objs[obn].frame = 0;
-	objs[obn].loop = 0;
-	objs[obn].view = -1;
+	_G(objs)[obn].cycling = 0;
+	_G(objs)[obn].frame = 0;
+	_G(objs)[obn].loop = 0;
+	_G(objs)[obn].view = -1;
 }
 
 int GetObjectGraphic(int obn) {
 	if (!is_valid_object(obn)) quit("!GetObjectGraphic: invalid object specified");
-	return objs[obn].num;
+	return _G(objs)[obn].num;
 }
 
 int GetObjectY(int objj) {
 	if (!is_valid_object(objj)) quit("!GetObjectY: invalid object number");
-	return objs[objj].y;
+	return _G(objs)[objj].y;
 }
 
 int IsObjectAnimating(int objj) {
 	if (!is_valid_object(objj)) quit("!IsObjectAnimating: invalid object number");
-	return (objs[objj].cycling != 0) ? 1 : 0;
+	return (_G(objs)[objj].cycling != 0) ? 1 : 0;
 }
 
 int IsObjectMoving(int objj) {
 	if (!is_valid_object(objj)) quit("!IsObjectMoving: invalid object number");
-	return (objs[objj].moving > 0) ? 1 : 0;
+	return (_G(objs)[objj].moving > 0) ? 1 : 0;
 }
 
 void SetObjectPosition(int objj, int tox, int toy) {
 	if (!is_valid_object(objj))
 		quit("!SetObjectPosition: invalid object number");
 
-	if (objs[objj].moving > 0) {
+	if (_G(objs)[objj].moving > 0) {
 		debug_script_warn("Object.SetPosition: cannot set position while object is moving");
 		return;
 	}
 
-	objs[objj].x = tox;
-	objs[objj].y = toy;
+	_G(objs)[objj].x = tox;
+	_G(objs)[objj].y = toy;
 }
 
 void GetObjectName(int obj, char *buffer) {
@@ -385,9 +378,9 @@ void MoveObjectDirect(int objj, int xx, int yy, int spp) {
 void SetObjectClickable(int cha, int clik) {
 	if (!is_valid_object(cha))
 		quit("!SetObjectClickable: Invalid object specified");
-	objs[cha].flags &= ~OBJF_NOINTERACT;
+	_G(objs)[cha].flags &= ~OBJF_NOINTERACT;
 	if (clik == 0)
-		objs[cha].flags |= OBJF_NOINTERACT;
+		_G(objs)[cha].flags |= OBJF_NOINTERACT;
 }
 
 void SetObjectIgnoreWalkbehinds(int cha, int clik) {
@@ -395,9 +388,9 @@ void SetObjectIgnoreWalkbehinds(int cha, int clik) {
 		quit("!SetObjectIgnoreWalkbehinds: Invalid object specified");
 	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;
+	_G(objs)[cha].flags &= ~OBJF_NOWALKBEHINDS;
 	if (clik)
-		objs[cha].flags |= OBJF_NOWALKBEHINDS;
+		_G(objs)[cha].flags |= OBJF_NOWALKBEHINDS;
 	// clear the cache
 	_G(objcache)[cha].ywas = -9999;
 }
@@ -428,10 +421,10 @@ void RunObjectInteraction(int aa, int mood) {
 		run_interaction_script(_GP(thisroom).Objects[aa].EventHandlers.get(), 4);  // any click on obj
 	} else {
 		if (passon >= 0) {
-			if (run_interaction_event(&croom->intrObject[aa], passon, 4, (passon == 3)))
+			if (run_interaction_event(&_G(croom)->intrObject[aa], passon, 4, (passon == 3)))
 				return;
 		}
-		run_interaction_event(&croom->intrObject[aa], 4); // any click on obj
+		run_interaction_event(&_G(croom)->intrObject[aa], 4); // any click on obj
 	}
 }
 
@@ -444,7 +437,7 @@ int AreObjectsColliding(int obj1, int obj2) {
 
 int GetThingRect(int thing, _Rect *rect) {
 	if (is_valid_character(thing)) {
-		if (_GP(game).chars[thing].room != displayed_room)
+		if (_GP(game).chars[thing].room != _G(displayed_room))
 			return 0;
 
 		int charwid = game_to_data_coord(GetCharacterWidth(thing));
@@ -454,12 +447,12 @@ int GetThingRect(int thing, _Rect *rect) {
 		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)
+		if (_G(objs)[objid].on != 1)
 			return 0;
-		rect->x1 = objs[objid].x;
-		rect->x2 = objs[objid].x + game_to_data_coord(objs[objid].get_width());
-		rect->y1 = objs[objid].y - game_to_data_coord(objs[objid].get_height());
-		rect->y2 = objs[objid].y;
+		rect->x1 = _G(objs)[objid].x;
+		rect->x2 = _G(objs)[objid].x + game_to_data_coord(_G(objs)[objid].get_width());
+		rect->y1 = _G(objs)[objid].y - game_to_data_coord(_G(objs)[objid].get_height());
+		rect->y2 = _G(objs)[objid].y;
 	} else
 		quit("!AreThingsOverlapping: invalid parameter");
 
@@ -499,11 +492,11 @@ int AreThingsOverlapping(int thing1, int thing2) {
 int GetObjectProperty(int hss, const char *property) {
 	if (!is_valid_object(hss))
 		quit("!GetObjectProperty: invalid object");
-	return get_int_property(_GP(thisroom).Objects[hss].Properties, croom->objProps[hss], property);
+	return get_int_property(_GP(thisroom).Objects[hss].Properties, _G(croom)->objProps[hss], property);
 }
 
 void GetObjectPropertyText(int item, const char *property, char *bufer) {
-	get_text_property(_GP(thisroom).Objects[item].Properties, croom->objProps[item], property, bufer);
+	get_text_property(_GP(thisroom).Objects[item].Properties, _G(croom)->objProps[item], property, bufer);
 }
 
 Bitmap *GetObjectImage(int obj, int *isFlipped) {
@@ -516,7 +509,7 @@ Bitmap *GetObjectImage(int obj, int *isFlipped) {
 			return actsps[obj];
 		}
 	}
-	return _GP(spriteset)[objs[obj].num];
+	return _GP(spriteset)[_G(objs)[obj].num];
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/ac/global_region.cpp b/engines/ags/engine/ac/global_region.cpp
index a8d69526fc..4632666c3d 100644
--- a/engines/ags/engine/ac/global_region.cpp
+++ b/engines/ags/engine/ac/global_region.cpp
@@ -36,8 +36,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-
-extern RoomStatus *croom;
 extern const char *evblockbasename;
 extern int evblocknum;
 
@@ -61,7 +59,7 @@ int GetRegionIDAtRoom(int xxx, int yyy) {
 
 	int hsthere = _GP(thisroom).RegionMask->GetPixel(xxx, yyy);
 	if (hsthere <= 0 || hsthere >= MAX_ROOM_REGIONS) return 0;
-	if (croom->region_enabled[hsthere] == 0) return 0;
+	if (_G(croom)->region_enabled[hsthere] == 0) return 0;
 	return hsthere;
 }
 
@@ -112,7 +110,7 @@ void DisableRegion(int hsnum) {
 	if ((hsnum < 0) || (hsnum >= MAX_ROOM_REGIONS))
 		quit("!DisableRegion: invalid region specified");
 
-	croom->region_enabled[hsnum] = 0;
+	_G(croom)->region_enabled[hsnum] = 0;
 	debug_script_log("Region %d disabled", hsnum);
 }
 
@@ -120,7 +118,7 @@ void EnableRegion(int hsnum) {
 	if ((hsnum < 0) || (hsnum >= MAX_ROOM_REGIONS))
 		quit("!EnableRegion: invalid region specified");
 
-	croom->region_enabled[hsnum] = 1;
+	_G(croom)->region_enabled[hsnum] = 1;
 	debug_script_log("Region %d enabled", hsnum);
 }
 
@@ -161,7 +159,7 @@ void RunRegionInteraction(int regnum, int mood) {
 	if (_GP(thisroom).Regions[regnum].EventHandlers != nullptr) {
 		run_interaction_script(_GP(thisroom).Regions[regnum].EventHandlers.get(), mood);
 	} else {
-		run_interaction_event(&croom->intrRegion[regnum], mood);
+		run_interaction_event(&_G(croom)->intrRegion[regnum], mood);
 	}
 
 	evblockbasename = oldbasename;
diff --git a/engines/ags/engine/ac/global_room.cpp b/engines/ags/engine/ac/global_room.cpp
index 3ffc01945d..25f0756c01 100644
--- a/engines/ags/engine/ac/global_room.cpp
+++ b/engines/ags/engine/ac/global_room.cpp
@@ -44,11 +44,8 @@ namespace AGS3 {
 
 using namespace Shared;
 
-
-
-extern RoomStatus *croom;
 extern CharacterInfo *playerchar;
-extern int displayed_room;
+
 extern int in_enters_screen;
 extern int in_leaves_screen;
 extern int in_inv_screen, inv_screen_newroom;
@@ -85,7 +82,7 @@ void NewRoom(int nrnum) {
 	if (nrnum < 0)
 		quitprintf("!NewRoom: room change requested to invalid room number %d.", nrnum);
 
-	if (displayed_room < 0) {
+	if (_G(displayed_room) < 0) {
 		// called from game_start; change the room where the game will start
 		playerchar->room = nrnum;
 		return;
@@ -151,7 +148,7 @@ void NewRoomNPC(int charid, int nrnum, int newx, int newy) {
 }
 
 void ResetRoom(int nrnum) {
-	if (nrnum == displayed_room)
+	if (nrnum == _G(displayed_room))
 		quit("!ResetRoom: cannot reset current room");
 	if ((nrnum < 0) | (nrnum >= MAX_ROOMS))
 		quit("!ResetRoom: invalid room number");
@@ -197,7 +194,7 @@ int HasBeenToRoom(int roomnum) {
 }
 
 void GetRoomPropertyText(const char *property, char *bufer) {
-	get_text_property(_GP(thisroom).Properties, croom->roomProps, property, bufer);
+	get_text_property(_GP(thisroom).Properties, _G(croom)->roomProps, property, bufer);
 }
 
 void SetBackgroundFrame(int frnum) {
diff --git a/engines/ags/engine/ac/global_screen.cpp b/engines/ags/engine/ac/global_screen.cpp
index aadce3e7e6..041ba55277 100644
--- a/engines/ags/engine/ac/global_screen.cpp
+++ b/engines/ags/engine/ac/global_screen.cpp
@@ -42,7 +42,7 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern IGraphicsDriver *gfxDriver;
-extern AGSPlatformDriver *platform;
+
 extern color palette[256];
 extern unsigned int loopcounter;
 
@@ -71,7 +71,7 @@ void ShakeScreen(int severe) {
 	if (gfxDriver->RequiresFullRedrawEachFrame()) {
 		for (int hh = 0; hh < 40; hh++) {
 			loopcounter++;
-			platform->Delay(50);
+			_G(platform)->Delay(50);
 
 			render_graphics();
 
@@ -82,7 +82,7 @@ void ShakeScreen(int severe) {
 		construct_game_scene();
 		gfxDriver->RenderToBackBuffer();
 		for (int hh = 0; hh < 40; hh++) {
-			platform->Delay(50);
+			_G(platform)->Delay(50);
 			const int yoff = hh % 2 == 0 ? 0 : severe;
 			_GP(play).shake_screen_yoff = yoff;
 			render_to_screen();
diff --git a/engines/ags/engine/ac/global_translation.cpp b/engines/ags/engine/ac/global_translation.cpp
index d37c24ee31..9290c3caa2 100644
--- a/engines/ags/engine/ac/global_translation.cpp
+++ b/engines/ags/engine/ac/global_translation.cpp
@@ -37,7 +37,7 @@ namespace AGS3 {
 using namespace AGS::Shared::Memory;
 
 
-extern AGSPlatformDriver *platform;
+
 extern TreeMap *transtree;
 extern char transFileName[MAX_PATH];
 
diff --git a/engines/ags/engine/ac/global_walkbehind.cpp b/engines/ags/engine/ac/global_walkbehind.cpp
index ae1f7cc67f..991ba58612 100644
--- a/engines/ags/engine/ac/global_walkbehind.cpp
+++ b/engines/ags/engine/ac/global_walkbehind.cpp
@@ -27,20 +27,20 @@
 #include "ags/engine/ac/roomstatus.h"
 #include "ags/engine/ac/walkbehind.h"
 #include "ags/engine/debugging/debug_log.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern RoomStatus *croom;
 extern int walk_behind_baselines_changed;
 
 void SetWalkBehindBase(int wa, int bl) {
 	if ((wa < 1) || (wa >= MAX_WALK_BEHINDS))
 		quit("!SetWalkBehindBase: invalid walk-behind area specified");
 
-	if (bl != croom->walkbehind_base[wa]) {
+	if (bl != _G(croom)->walkbehind_base[wa]) {
 		walk_behind_baselines_changed = 1;
 		invalidate_cached_walkbehinds();
-		croom->walkbehind_base[wa] = bl;
+		_G(croom)->walkbehind_base[wa] = bl;
 		debug_script_log("Walk-behind %d baseline changed to %d", wa, bl);
 	}
 }
diff --git a/engines/ags/engine/ac/hotspot.cpp b/engines/ags/engine/ac/hotspot.cpp
index 56794f24fc..656382cce0 100644
--- a/engines/ags/engine/ac/hotspot.cpp
+++ b/engines/ags/engine/ac/hotspot.cpp
@@ -42,8 +42,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern RoomStatus *croom;
-
 void Hotspot_SetEnabled(ScriptHotspot *hss, int newval) {
 	if (newval)
 		EnableHotspot(hss->id);
@@ -52,7 +50,7 @@ void Hotspot_SetEnabled(ScriptHotspot *hss, int newval) {
 }
 
 int Hotspot_GetEnabled(ScriptHotspot *hss) {
-	return croom->hotspot_enabled[hss->id];
+	return _G(croom)->hotspot_enabled[hss->id];
 }
 
 int Hotspot_GetID(ScriptHotspot *hss) {
@@ -97,30 +95,30 @@ void Hotspot_RunInteraction(ScriptHotspot *hss, int mood) {
 }
 
 int Hotspot_GetProperty(ScriptHotspot *hss, const char *property) {
-	return get_int_property(_GP(thisroom).Hotspots[hss->id].Properties, croom->hsProps[hss->id], property);
+	return get_int_property(_GP(thisroom).Hotspots[hss->id].Properties, _G(croom)->hsProps[hss->id], property);
 }
 
 void Hotspot_GetPropertyText(ScriptHotspot *hss, const char *property, char *bufer) {
-	get_text_property(_GP(thisroom).Hotspots[hss->id].Properties, croom->hsProps[hss->id], property, bufer);
+	get_text_property(_GP(thisroom).Hotspots[hss->id].Properties, _G(croom)->hsProps[hss->id], property, bufer);
 
 }
 
 const char *Hotspot_GetTextProperty(ScriptHotspot *hss, const char *property) {
-	return get_text_property_dynamic_string(_GP(thisroom).Hotspots[hss->id].Properties, croom->hsProps[hss->id], property);
+	return get_text_property_dynamic_string(_GP(thisroom).Hotspots[hss->id].Properties, _G(croom)->hsProps[hss->id], property);
 }
 
 bool Hotspot_SetProperty(ScriptHotspot *hss, const char *property, int value) {
-	return set_int_property(croom->hsProps[hss->id], property, value);
+	return set_int_property(_G(croom)->hsProps[hss->id], property, value);
 }
 
 bool Hotspot_SetTextProperty(ScriptHotspot *hss, const char *property, const char *value) {
-	return set_text_property(croom->hsProps[hss->id], property, value);
+	return set_text_property(_G(croom)->hsProps[hss->id], property, value);
 }
 
 int get_hotspot_at(int xpp, int ypp) {
 	int onhs = _GP(thisroom).HotspotMask->GetPixel(room_to_mask_coord(xpp), room_to_mask_coord(ypp));
 	if (onhs <= 0 || onhs >= MAX_ROOM_HOTSPOTS) return 0;
-	if (croom->hotspot_enabled[onhs] == 0) return 0;
+	if (_G(croom)->hotspot_enabled[onhs] == 0) return 0;
 	return onhs;
 }
 
diff --git a/engines/ags/engine/ac/invwindow.cpp b/engines/ags/engine/ac/invwindow.cpp
index 75b3ca189e..174773ab58 100644
--- a/engines/ags/engine/ac/invwindow.cpp
+++ b/engines/ags/engine/ac/invwindow.cpp
@@ -61,7 +61,7 @@ extern int mouse_ifacebut_xoffs, mouse_ifacebut_yoffs;
 
 extern int evblocknum;
 extern CharacterInfo *playerchar;
-extern AGSPlatformDriver *platform;
+
 
 
 
diff --git a/engines/ags/engine/ac/mouse.cpp b/engines/ags/engine/ac/mouse.cpp
index 9b360edac3..9fec539b14 100644
--- a/engines/ags/engine/ac/mouse.cpp
+++ b/engines/ags/engine/ac/mouse.cpp
@@ -336,7 +336,7 @@ void Mouse_EnableControl(bool on) {
 	// Whether mouse movement control is supported by the engine - this is
 	// determined on per platform basis. Some builds may not have such
 	// capability, e.g. because of how backend library implements mouse utils.
-	bool can_control_mouse = platform->IsMouseControlSupported(is_windowed);
+	bool can_control_mouse = _G(platform)->IsMouseControlSupported(is_windowed);
 	// The resulting choice is made based on two aforementioned factors.
 	on &= should_control_mouse && can_control_mouse;
 	if (on)
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index 624c835f14..3eacf82319 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -55,13 +55,9 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern RoomStatus *croom;
-extern RoomObject *objs;
-
 extern Bitmap *walkable_areas_temp;
 extern IGraphicsDriver *gfxDriver;
 
-
 int Object_IsCollidingWithObject(ScriptObject *objj, ScriptObject *obj2) {
 	return AreObjectsColliding(objj->id, obj2->id);
 }
@@ -81,7 +77,7 @@ ScriptObject *GetObjectAtRoom(int x, int y) {
 }
 
 AGS_INLINE int is_valid_object(int obtest) {
-	if ((obtest < 0) || (obtest >= croom->numobj)) return 0;
+	if ((obtest < 0) || (obtest >= _G(croom)->numobj)) return 0;
 	return 1;
 }
 
@@ -96,7 +92,7 @@ void Object_RemoveTint(ScriptObject *objj) {
 void Object_SetView(ScriptObject *objj, int view, int loop, int frame) {
 	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];
+		auto &obj = _G(objs)[objj->id];
 		if (loop < 0) loop = obj.loop;
 		if (frame < 0) frame = obj.frame;
 		const int vidx = view - 1;
@@ -115,7 +111,7 @@ int Object_GetTransparency(ScriptObject *objj) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.Transparent: invalid object number specified");
 
-	return GfxDef::LegacyTrans255ToTrans100(objs[objj->id].transparent);
+	return GfxDef::LegacyTrans255ToTrans100(_G(objs)[objj->id].transparent);
 }
 
 void Object_SetBaseline(ScriptObject *objj, int basel) {
@@ -152,9 +148,9 @@ void Object_StopAnimating(ScriptObject *objj) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.StopAnimating: invalid object number");
 
-	if (objs[objj->id].cycling) {
-		objs[objj->id].cycling = 0;
-		objs[objj->id].wait = 0;
+	if (_G(objs)[objj->id].cycling) {
+		_G(objs)[objj->id].cycling = 0;
+		_G(objs)[objj->id].wait = 0;
 	}
 }
 
@@ -174,21 +170,21 @@ void Object_SetVisible(ScriptObject *objj, int onoroff) {
 }
 
 int Object_GetView(ScriptObject *objj) {
-	if (objs[objj->id].view < 0)
+	if (_G(objs)[objj->id].view < 0)
 		return 0;
-	return objs[objj->id].view + 1;
+	return _G(objs)[objj->id].view + 1;
 }
 
 int Object_GetLoop(ScriptObject *objj) {
-	if (objs[objj->id].view < 0)
+	if (_G(objs)[objj->id].view < 0)
 		return 0;
-	return objs[objj->id].loop;
+	return _G(objs)[objj->id].loop;
 }
 
 int Object_GetFrame(ScriptObject *objj) {
-	if (objs[objj->id].view < 0)
+	if (_G(objs)[objj->id].view < 0)
 		return 0;
-	return objs[objj->id].frame;
+	return _G(objs)[objj->id].frame;
 }
 
 int Object_GetVisible(ScriptObject *objj) {
@@ -205,7 +201,7 @@ int Object_GetGraphic(ScriptObject *objj) {
 
 int GetObjectX(int objj) {
 	if (!is_valid_object(objj)) quit("!GetObjectX: invalid object number");
-	return objs[objj].x;
+	return _G(objs)[objj].x;
 }
 
 int Object_GetX(ScriptObject *objj) {
@@ -225,15 +221,15 @@ int Object_GetMoving(ScriptObject *objj) {
 }
 
 bool Object_HasExplicitLight(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_light();
+	return _G(objs)[obj->id].has_explicit_light();
 }
 
 bool Object_HasExplicitTint(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_tint();
+	return _G(objs)[obj->id].has_explicit_tint();
 }
 
 int Object_GetLightLevel(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_light() ? objs[obj->id].tint_light : 0;
+	return _G(objs)[obj->id].has_explicit_light() ? _G(objs)[obj->id].tint_light : 0;
 }
 
 void Object_SetLightLevel(ScriptObject *objj, int light_level) {
@@ -241,29 +237,29 @@ void Object_SetLightLevel(ScriptObject *objj, int light_level) {
 	if (!is_valid_object(obj))
 		quit("!SetObjectTint: invalid object number specified");
 
-	objs[obj].tint_light = light_level;
-	objs[obj].flags &= ~OBJF_HASTINT;
-	objs[obj].flags |= OBJF_HASLIGHT;
+	_G(objs)[obj].tint_light = light_level;
+	_G(objs)[obj].flags &= ~OBJF_HASTINT;
+	_G(objs)[obj].flags |= OBJF_HASLIGHT;
 }
 
 int Object_GetTintRed(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_tint() ? objs[obj->id].tint_r : 0;
+	return _G(objs)[obj->id].has_explicit_tint() ? _G(objs)[obj->id].tint_r : 0;
 }
 
 int Object_GetTintGreen(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_tint() ? objs[obj->id].tint_g : 0;
+	return _G(objs)[obj->id].has_explicit_tint() ? _G(objs)[obj->id].tint_g : 0;
 }
 
 int Object_GetTintBlue(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_tint() ? objs[obj->id].tint_b : 0;
+	return _G(objs)[obj->id].has_explicit_tint() ? _G(objs)[obj->id].tint_b : 0;
 }
 
 int Object_GetTintSaturation(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_tint() ? objs[obj->id].tint_level : 0;
+	return _G(objs)[obj->id].has_explicit_tint() ? _G(objs)[obj->id].tint_level : 0;
 }
 
 int Object_GetTintLuminance(ScriptObject *obj) {
-	return objs[obj->id].has_explicit_tint() ? ((objs[obj->id].tint_light * 10) / 25) : 0;
+	return _G(objs)[obj->id].has_explicit_tint() ? ((_G(objs)[obj->id].tint_light * 10) / 25) : 0;
 }
 
 void Object_SetPosition(ScriptObject *objj, int xx, int yy) {
@@ -271,11 +267,11 @@ void Object_SetPosition(ScriptObject *objj, int xx, int yy) {
 }
 
 void Object_SetX(ScriptObject *objj, int xx) {
-	SetObjectPosition(objj->id, xx, objs[objj->id].y);
+	SetObjectPosition(objj->id, xx, _G(objs)[objj->id].y);
 }
 
 void Object_SetY(ScriptObject *objj, int yy) {
-	SetObjectPosition(objj->id, objs[objj->id].x, yy);
+	SetObjectPosition(objj->id, _G(objs)[objj->id].x, yy);
 }
 
 void Object_GetName(ScriptObject *objj, char *buffer) {
@@ -309,7 +305,7 @@ void Object_Move(ScriptObject *objj, int x, int y, int speed, int blocking, int
 	move_object(objj->id, x, y, speed, direct);
 
 	if ((blocking == BLOCKING) || (blocking == 1))
-		GameLoopUntilValueIsZero(&objs[objj->id].moving);
+		GameLoopUntilValueIsZero(&_G(objs)[objj->id].moving);
 	else if ((blocking != IN_BACKGROUND) && (blocking != 0))
 		quit("Object.Move: invalid BLOCKING paramter");
 }
@@ -322,14 +318,14 @@ int Object_GetClickable(ScriptObject *objj) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.Clickable: Invalid object specified");
 
-	if (objs[objj->id].flags & OBJF_NOINTERACT)
+	if (_G(objs)[objj->id].flags & OBJF_NOINTERACT)
 		return 0;
 	return 1;
 }
 
 void Object_SetManualScaling(ScriptObject *objj, bool on) {
-	if (on) objs[objj->id].flags &= ~OBJF_USEROOMSCALING;
-	else objs[objj->id].flags |= OBJF_USEROOMSCALING;
+	if (on) _G(objs)[objj->id].flags &= ~OBJF_USEROOMSCALING;
+	else _G(objs)[objj->id].flags |= OBJF_USEROOMSCALING;
 	// clear the cache
 	_G(objcache)[objj->id].ywas = -9999;
 }
@@ -338,7 +334,7 @@ void Object_SetIgnoreScaling(ScriptObject *objj, int newval) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.IgnoreScaling: Invalid object specified");
 	if (newval)
-		objs[objj->id].zoom = 100; // compatibility, for before manual scaling existed
+		_G(objs)[objj->id].zoom = 100; // compatibility, for before manual scaling existed
 	Object_SetManualScaling(objj, newval != 0);
 }
 
@@ -346,52 +342,52 @@ int Object_GetIgnoreScaling(ScriptObject *objj) {
 	if (!is_valid_object(objj->id))
 		quit("!Object.IgnoreScaling: Invalid object specified");
 
-	if (objs[objj->id].flags & OBJF_USEROOMSCALING)
+	if (_G(objs)[objj->id].flags & OBJF_USEROOMSCALING)
 		return 0;
 	return 1;
 }
 
 int Object_GetScaling(ScriptObject *objj) {
-	return objs[objj->id].zoom;
+	return _G(objs)[objj->id].zoom;
 }
 
 void Object_SetScaling(ScriptObject *objj, int zoomlevel) {
-	if ((objs[objj->id].flags & OBJF_USEROOMSCALING) != 0) {
+	if ((_G(objs)[objj->id].flags & OBJF_USEROOMSCALING) != 0) {
 		debug_script_warn("Object.Scaling: cannot set property unless ManualScaling is enabled");
 		return;
 	}
 	int zoom_fixed = Math::Clamp(zoomlevel, 1, (int)(INT16_MAX)); // RoomObject.zoom is int16
 	if (zoomlevel != zoom_fixed)
 		debug_script_warn("Object.Scaling: scaling level must be between 1 and %d%%", (int)(INT16_MAX));
-	objs[objj->id].zoom = zoom_fixed;
+	_G(objs)[objj->id].zoom = zoom_fixed;
 }
 
 void Object_SetSolid(ScriptObject *objj, int solid) {
-	objs[objj->id].flags &= ~OBJF_SOLID;
+	_G(objs)[objj->id].flags &= ~OBJF_SOLID;
 	if (solid)
-		objs[objj->id].flags |= OBJF_SOLID;
+		_G(objs)[objj->id].flags |= OBJF_SOLID;
 }
 
 int Object_GetSolid(ScriptObject *objj) {
-	if (objs[objj->id].flags & OBJF_SOLID)
+	if (_G(objs)[objj->id].flags & OBJF_SOLID)
 		return 1;
 	return 0;
 }
 
 void Object_SetBlockingWidth(ScriptObject *objj, int bwid) {
-	objs[objj->id].blocking_width = bwid;
+	_G(objs)[objj->id].blocking_width = bwid;
 }
 
 int Object_GetBlockingWidth(ScriptObject *objj) {
-	return objs[objj->id].blocking_width;
+	return _G(objs)[objj->id].blocking_width;
 }
 
 void Object_SetBlockingHeight(ScriptObject *objj, int bhit) {
-	objs[objj->id].blocking_height = bhit;
+	_G(objs)[objj->id].blocking_height = bhit;
 }
 
 int Object_GetBlockingHeight(ScriptObject *objj) {
-	return objs[objj->id].blocking_height;
+	return _G(objs)[objj->id].blocking_height;
 }
 
 int Object_GetID(ScriptObject *objj) {
@@ -406,7 +402,7 @@ int Object_GetIgnoreWalkbehinds(ScriptObject *chaa) {
 	if (!is_valid_object(chaa->id))
 		quit("!Object.IgnoreWalkbehinds: Invalid object specified");
 
-	if (objs[chaa->id].flags & OBJF_NOWALKBEHINDS)
+	if (_G(objs)[chaa->id].flags & OBJF_NOWALKBEHINDS)
 		return 1;
 	return 0;
 }
@@ -418,15 +414,15 @@ void move_object(int objj, int tox, int toy, int spee, int ignwal) {
 
 	// AGS <= 2.61 uses MoveObject with spp=-1 internally instead of SetObjectPosition
 	if ((loaded_game_file_version <= kGameVersion_261) && (spee == -1)) {
-		objs[objj].x = tox;
-		objs[objj].y = toy;
+		_G(objs)[objj].x = tox;
+		_G(objs)[objj].y = toy;
 		return;
 	}
 
 	debug_script_log("Object %d start move to %d,%d", objj, tox, toy);
 
-	int objX = room_to_mask_coord(objs[objj].x);
-	int objY = room_to_mask_coord(objs[objj].y);
+	int objX = room_to_mask_coord(_G(objs)[objj].x);
+	int objY = room_to_mask_coord(_G(objs)[objj].y);
 	tox = room_to_mask_coord(tox);
 	toy = room_to_mask_coord(toy);
 
@@ -435,7 +431,7 @@ void move_object(int objj, int tox, int toy, int spee, int ignwal) {
 	int mslot = find_route(objX, objY, tox, toy, prepare_walkable_areas(-1), objj + 1, 1, ignwal);
 	set_color_depth(_GP(game).GetColorDepth());
 	if (mslot > 0) {
-		objs[objj].moving = mslot;
+		_G(objs)[objj].moving = mslot;
 		_G(mls)[mslot].direct = ignwal;
 		convert_move_path_to_room_resolution(&_G(mls)[mslot]);
 	}
@@ -454,19 +450,19 @@ void Object_GetPropertyText(ScriptObject *objj, const char *property, char *bufe
 }
 
 const char *Object_GetTextProperty(ScriptObject *objj, const char *property) {
-	return get_text_property_dynamic_string(_GP(thisroom).Objects[objj->id].Properties, croom->objProps[objj->id], property);
+	return get_text_property_dynamic_string(_GP(thisroom).Objects[objj->id].Properties, _G(croom)->objProps[objj->id], property);
 }
 
 bool Object_SetProperty(ScriptObject *objj, const char *property, int value) {
-	return set_int_property(croom->objProps[objj->id], property, value);
+	return set_int_property(_G(croom)->objProps[objj->id], property, value);
 }
 
 bool Object_SetTextProperty(ScriptObject *objj, const char *property, const char *value) {
-	return set_text_property(croom->objProps[objj->id], property, value);
+	return set_text_property(_G(croom)->objProps[objj->id], property, value);
 }
 
 void get_object_blocking_rect(int objid, int *x1, int *y1, int *width, int *y2) {
-	RoomObject *tehobj = &objs[objid];
+	RoomObject *tehobj = &_G(objs)[objid];
 	int cwidth, fromx;
 
 	if (tehobj->blocking_width < 1)
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 3b238377e4..85c1da2bbd 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -47,7 +47,7 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern int displayed_room;
+
 extern int face_talking;
 
 extern CharacterExtras *charextra;
@@ -248,7 +248,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 (_GP(game).chars[charid].room != displayed_room) {
+		if (_GP(game).chars[charid].room != _G(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/region.cpp b/engines/ags/engine/ac/region.cpp
index 6e84ca1cfd..0c7db276b4 100644
--- a/engines/ags/engine/ac/region.cpp
+++ b/engines/ags/engine/ac/region.cpp
@@ -40,7 +40,6 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern RoomStatus *croom;
 extern COLOR_MAP maincoltable;
 extern color palette[256];
 
@@ -109,7 +108,7 @@ void Region_SetEnabled(ScriptRegion *ssr, int enable) {
 }
 
 int Region_GetEnabled(ScriptRegion *ssr) {
-	return croom->region_enabled[ssr->id];
+	return _G(croom)->region_enabled[ssr->id];
 }
 
 int Region_GetID(ScriptRegion *ssr) {
diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index d9e245cab4..ef2e98f826 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -85,21 +85,15 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern RoomStatus *croom;
-extern int displayed_room;
-extern RoomObject *objs;
-extern AGSPlatformDriver *platform;
+
+
 extern int numevents;
 extern CharacterExtras *charextra;
 extern int done_es_error;
-extern int our_eip;
 extern Bitmap *walkareabackup, *walkable_areas_temp;
 
-extern int in_new_room, new_room_was;  // 1 in new room, 2 first time in new room, 3 loading saved game
-
 extern int in_leaves_screen;
 extern CharacterInfo *playerchar;
-extern int starting_room;
 extern unsigned int loopcounter;
 extern IDriverDependantBitmap *roomBackgroundBmp;
 extern IGraphicsDriver *gfxDriver;
@@ -121,7 +115,7 @@ int new_room_flags = 0;
 int gs_to_newroom = -1;
 
 ScriptDrawingSurface *Room_GetDrawingSurfaceForBackground(int backgroundNumber) {
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		quit("!Room.GetDrawingSurfaceForBackground: no room is currently loaded");
 
 	if (backgroundNumber == SCR_NO_VALUE) {
@@ -139,7 +133,7 @@ ScriptDrawingSurface *Room_GetDrawingSurfaceForBackground(int backgroundNumber)
 }
 
 ScriptDrawingSurface *Room_GetDrawingSurfaceForMask(RoomAreaMask mask) {
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		quit("!Room_GetDrawingSurfaceForMask: no room is currently loaded");
 	ScriptDrawingSurface *surface = new ScriptDrawingSurface();
 	surface->roomMaskType = mask;
@@ -148,7 +142,7 @@ ScriptDrawingSurface *Room_GetDrawingSurfaceForMask(RoomAreaMask mask) {
 }
 
 int Room_GetObjectCount() {
-	return croom->numobj;
+	return _G(croom)->numobj;
 }
 
 int Room_GetWidth() {
@@ -184,19 +178,19 @@ int Room_GetMusicOnLoad() {
 }
 
 int Room_GetProperty(const char *property) {
-	return get_int_property(_GP(thisroom).Properties, croom->roomProps, property);
+	return get_int_property(_GP(thisroom).Properties, _G(croom)->roomProps, property);
 }
 
 const char *Room_GetTextProperty(const char *property) {
-	return get_text_property_dynamic_string(_GP(thisroom).Properties, croom->roomProps, property);
+	return get_text_property_dynamic_string(_GP(thisroom).Properties, _G(croom)->roomProps, property);
 }
 
 bool Room_SetProperty(const char *property, int value) {
-	return set_int_property(croom->roomProps, property, value);
+	return set_int_property(_G(croom)->roomProps, property, value);
 }
 
 bool Room_SetTextProperty(const char *property, const char *value) {
-	return set_text_property(croom->roomProps, property, value);
+	return set_text_property(_G(croom)->roomProps, property, value);
 }
 
 const char *Room_GetMessages(int index) {
@@ -233,12 +227,12 @@ void convert_room_background_to_game_res() {
 
 
 void save_room_data_segment() {
-	croom->FreeScriptData();
+	_G(croom)->FreeScriptData();
 
-	croom->tsdatasize = _G(roominst)->globaldatasize;
-	if (croom->tsdatasize > 0) {
-		croom->tsdata = (char *)malloc(croom->tsdatasize + 10);
-		memcpy(croom->tsdata, &_G(roominst)->globaldata[0], croom->tsdatasize);
+	_G(croom)->tsdatasize = _G(roominst)->globaldatasize;
+	if (_G(croom)->tsdatasize > 0) {
+		_G(croom)->tsdata = (char *)malloc(_G(croom)->tsdatasize + 10);
+		memcpy(_G(croom)->tsdata, &_G(roominst)->globaldata[0], _G(croom)->tsdatasize);
 	}
 
 }
@@ -247,17 +241,17 @@ void unload_old_room() {
 	int ff;
 
 	// if switching games on restore, don't do this
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		return;
 
-	debug_script_log("Unloading room %d", displayed_room);
+	debug_script_log("Unloading room %d", _G(displayed_room));
 
 	current_fade_out_effect();
 
 	dispose_room_drawdata();
 
-	for (ff = 0; ff < croom->numobj; ff++)
-		objs[ff].moving = 0;
+	for (ff = 0; ff < _G(croom)->numobj; ff++)
+		_G(objs)[ff].moving = 0;
 
 	if (!_GP(play).ambient_sounds_persist) {
 		for (ff = 1; ff < MAX_SOUND_CHANNELS; ff++)
@@ -272,14 +266,14 @@ void unload_old_room() {
 		roomBackgroundBmp = nullptr;
 	}
 
-	if (croom == nullptr) ;
+	if (_G(croom) == nullptr) ;
 	else if (_G(roominst) != nullptr) {
 		save_room_data_segment();
 		delete _G(roominstFork);
 		delete _G(roominst);
 		_G(roominstFork) = nullptr;
 		_G(roominst) = nullptr;
-	} else croom->tsdatasize = 0;
+	} else _G(croom)->tsdatasize = 0;
 	memset(&_GP(play).walkable_areas_on[0], 1, MAX_WALK_AREAS + 1);
 	_GP(play).bg_frame = 0;
 	_GP(play).bg_frame_locked = 0;
@@ -289,7 +283,7 @@ void unload_old_room() {
 	for (ff = 0; ff < MAX_ROOM_BGFRAMES; ff++)
 		_GP(play).raw_modified[ff] = 0;
 	for (size_t i = 0; i < _GP(thisroom).LocalVariables.size() && i < MAX_GLOBAL_VARIABLES; ++i)
-		croom->interactionVariableValues[i] = _GP(thisroom).LocalVariables[i].Value;
+		_G(croom)->interactionVariableValues[i] = _GP(thisroom).LocalVariables[i].Value;
 
 	// wipe the character cache when we change rooms
 	for (ff = 0; ff < _GP(game).numcharacters; ff++) {
@@ -305,7 +299,7 @@ void unload_old_room() {
 	_GP(play).swap_portrait_lastchar = -1;
 	_GP(play).swap_portrait_lastlastchar = -1;
 
-	for (ff = 0; ff < croom->numobj; ff++) {
+	for (ff = 0; ff < _G(croom)->numobj; ff++) {
 		// un-export the object's script object
 		if (_G(objectScriptObjNames)[ff].IsEmpty())
 			continue;
@@ -448,7 +442,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	// created meanwhile it will have this color depth by default, which may
 	// lead to unexpected errors.
 	set_color_depth(8);
-	displayed_room = newnum;
+	_G(displayed_room) = newnum;
 
 	room_filename.Format("room%d.crm", newnum);
 	if (newnum == 0) {
@@ -463,7 +457,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	update_polled_stuff_if_runtime();
 
 	// load the room from disk
-	our_eip = 200;
+	_G(our_eip) = 200;
 	_GP(thisroom).GameID = NO_GAME_ID_IN_ROOM_FILE;
 	load_room(room_filename, &_GP(thisroom), _GP(game).IsLegacyHiRes(), _GP(game).SpriteInfos);
 
@@ -475,7 +469,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	convert_room_coordinates_to_data_res(&_GP(thisroom));
 
 	update_polled_stuff_if_runtime();
-	our_eip = 201;
+	_G(our_eip) = 201;
 	/*  // apparently, doing this stops volume spiking between tracks
 	if (_GP(thisroom).Options.StartupMusic>0) {
 	stopmusic();
@@ -505,14 +499,14 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 
 	update_polled_stuff_if_runtime();
 
-	our_eip = 202;
+	_G(our_eip) = 202;
 	// Update game viewports
 	if (_GP(game).IsLegacyLetterbox())
 		update_letterbox_mode();
 	SetMouseBounds(0, 0, 0, 0);
 
-	our_eip = 203;
-	in_new_room = 1;
+	_G(our_eip) = 203;
+	_G(in_new_room) = 1;
 
 	// walkable_areas_temp is used by the pathfinder to generate a
 	// copy of the walkable areas - allocate it here to save time later
@@ -525,7 +519,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	// copy the walls screen
 	walkareabackup = BitmapHelper::CreateBitmapCopy(_GP(thisroom).WalkAreaMask.get());
 
-	our_eip = 204;
+	_G(our_eip) = 204;
 	update_polled_stuff_if_runtime();
 	redo_walkable_areas();
 	update_polled_stuff_if_runtime();
@@ -535,7 +529,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	recache_walk_behinds();
 	update_polled_stuff_if_runtime();
 
-	our_eip = 205;
+	_G(our_eip) = 205;
 	// setup objects
 	if (forchar != nullptr) {
 		// if not restoring a game, always reset this room
@@ -546,74 +540,74 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 		memset(&_GP(troom).region_enabled[0], 1, MAX_ROOM_REGIONS);
 	}
 	if ((newnum >= 0) & (newnum < MAX_ROOMS))
-		croom = getRoomStatus(newnum);
-	else croom = &_GP(troom);
+		_G(croom) = getRoomStatus(newnum);
+	else _G(croom) = &_GP(troom);
 
-	if (croom->beenhere > 0) {
+	if (_G(croom)->beenhere > 0) {
 		// if we've been here before, save the Times Run information
 		// since we will overwrite the actual NewInteraction structs
 		// (cos they have pointers and this might have been loaded from
 		// a save game)
 		if (_GP(thisroom).EventHandlers == nullptr) {
 			// legacy interactions
-			_GP(thisroom).Interaction->CopyTimesRun(croom->intrRoom);
+			_GP(thisroom).Interaction->CopyTimesRun(_G(croom)->intrRoom);
 			for (cc = 0; cc < MAX_ROOM_HOTSPOTS; cc++)
-				_GP(thisroom).Hotspots[cc].Interaction->CopyTimesRun(croom->intrHotspot[cc]);
+				_GP(thisroom).Hotspots[cc].Interaction->CopyTimesRun(_G(croom)->intrHotspot[cc]);
 			for (cc = 0; cc < MAX_ROOM_OBJECTS; cc++)
-				_GP(thisroom).Objects[cc].Interaction->CopyTimesRun(croom->intrObject[cc]);
+				_GP(thisroom).Objects[cc].Interaction->CopyTimesRun(_G(croom)->intrObject[cc]);
 			for (cc = 0; cc < MAX_ROOM_REGIONS; cc++)
-				_GP(thisroom).Regions[cc].Interaction->CopyTimesRun(croom->intrRegion[cc]);
+				_GP(thisroom).Regions[cc].Interaction->CopyTimesRun(_G(croom)->intrRegion[cc]);
 		}
 	}
-	if (croom->beenhere == 0) {
-		croom->numobj = _GP(thisroom).ObjectCount;
-		croom->tsdatasize = 0;
-		for (cc = 0; cc < croom->numobj; cc++) {
-			croom->obj[cc].x = _GP(thisroom).Objects[cc].X;
-			croom->obj[cc].y = _GP(thisroom).Objects[cc].Y;
-			croom->obj[cc].num = _GP(thisroom).Objects[cc].Sprite;
-			croom->obj[cc].on = _GP(thisroom).Objects[cc].IsOn;
-			croom->obj[cc].view = -1;
-			croom->obj[cc].loop = 0;
-			croom->obj[cc].frame = 0;
-			croom->obj[cc].wait = 0;
-			croom->obj[cc].transparent = 0;
-			croom->obj[cc].moving = -1;
-			croom->obj[cc].flags = _GP(thisroom).Objects[cc].Flags;
-			croom->obj[cc].baseline = -1;
-			croom->obj[cc].zoom = 100;
-			croom->obj[cc].last_width = 0;
-			croom->obj[cc].last_height = 0;
-			croom->obj[cc].blocking_width = 0;
-			croom->obj[cc].blocking_height = 0;
+	if (_G(croom)->beenhere == 0) {
+		_G(croom)->numobj = _GP(thisroom).ObjectCount;
+		_G(croom)->tsdatasize = 0;
+		for (cc = 0; cc < _G(croom)->numobj; cc++) {
+			_G(croom)->obj[cc].x = _GP(thisroom).Objects[cc].X;
+			_G(croom)->obj[cc].y = _GP(thisroom).Objects[cc].Y;
+			_G(croom)->obj[cc].num = _GP(thisroom).Objects[cc].Sprite;
+			_G(croom)->obj[cc].on = _GP(thisroom).Objects[cc].IsOn;
+			_G(croom)->obj[cc].view = -1;
+			_G(croom)->obj[cc].loop = 0;
+			_G(croom)->obj[cc].frame = 0;
+			_G(croom)->obj[cc].wait = 0;
+			_G(croom)->obj[cc].transparent = 0;
+			_G(croom)->obj[cc].moving = -1;
+			_G(croom)->obj[cc].flags = _GP(thisroom).Objects[cc].Flags;
+			_G(croom)->obj[cc].baseline = -1;
+			_G(croom)->obj[cc].zoom = 100;
+			_G(croom)->obj[cc].last_width = 0;
+			_G(croom)->obj[cc].last_height = 0;
+			_G(croom)->obj[cc].blocking_width = 0;
+			_G(croom)->obj[cc].blocking_height = 0;
 			if (_GP(thisroom).Objects[cc].Baseline >= 0)
-				//        croom->obj[cc].baseoffs=_GP(thisroom).Objects.Baseline[cc]-_GP(thisroom).Objects[cc].y;
-				croom->obj[cc].baseline = _GP(thisroom).Objects[cc].Baseline;
+				//        _G(croom)->obj[cc].baseoffs=_GP(thisroom).Objects.Baseline[cc]-_GP(thisroom).Objects[cc].y;
+				_G(croom)->obj[cc].baseline = _GP(thisroom).Objects[cc].Baseline;
 		}
 		for (size_t i = 0; i < (size_t)MAX_WALK_BEHINDS; ++i)
-			croom->walkbehind_base[i] = _GP(thisroom).WalkBehinds[i].Baseline;
-		for (cc = 0; cc < MAX_FLAGS; cc++) croom->flagstates[cc] = 0;
+			_G(croom)->walkbehind_base[i] = _GP(thisroom).WalkBehinds[i].Baseline;
+		for (cc = 0; cc < MAX_FLAGS; cc++) _G(croom)->flagstates[cc] = 0;
 
 		/*    // we copy these structs for the Score column to work
-		croom->misccond=_GP(thisroom).misccond;
+		_G(croom)->misccond=_GP(thisroom).misccond;
 		for (cc=0;cc<MAX_ROOM_HOTSPOTS;cc++)
-		croom->hscond[cc]=_GP(thisroom).hscond[cc];
+		_G(croom)->hscond[cc]=_GP(thisroom).hscond[cc];
 		for (cc=0;cc<MAX_ROOM_OBJECTS;cc++)
-		croom->objcond[cc]=_GP(thisroom).objcond[cc];*/
+		_G(croom)->objcond[cc]=_GP(thisroom).objcond[cc];*/
 
 		for (cc = 0; cc < MAX_ROOM_HOTSPOTS; cc++) {
-			croom->hotspot_enabled[cc] = 1;
+			_G(croom)->hotspot_enabled[cc] = 1;
 		}
 		for (cc = 0; cc < MAX_ROOM_REGIONS; cc++) {
-			croom->region_enabled[cc] = 1;
+			_G(croom)->region_enabled[cc] = 1;
 		}
 
-		croom->beenhere = 1;
-		in_new_room = 2;
+		_G(croom)->beenhere = 1;
+		_G(in_new_room) = 2;
 	} else {
 		// We have been here before
 		for (size_t i = 0; i < _GP(thisroom).LocalVariables.size() && i < (size_t)MAX_GLOBAL_VARIABLES; ++i)
-			_GP(thisroom).LocalVariables[i].Value = croom->interactionVariableValues[i];
+			_GP(thisroom).LocalVariables[i].Value = _G(croom)->interactionVariableValues[i];
 	}
 
 	update_polled_stuff_if_runtime();
@@ -621,24 +615,24 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	if (_GP(thisroom).EventHandlers == nullptr) {
 		// legacy interactions
 		// copy interactions from room file into our temporary struct
-		croom->intrRoom = *_GP(thisroom).Interaction;
+		_G(croom)->intrRoom = *_GP(thisroom).Interaction;
 		for (cc = 0; cc < MAX_ROOM_HOTSPOTS; cc++)
-			croom->intrHotspot[cc] = *_GP(thisroom).Hotspots[cc].Interaction;
+			_G(croom)->intrHotspot[cc] = *_GP(thisroom).Hotspots[cc].Interaction;
 		for (cc = 0; cc < MAX_ROOM_OBJECTS; cc++)
-			croom->intrObject[cc] = *_GP(thisroom).Objects[cc].Interaction;
+			_G(croom)->intrObject[cc] = *_GP(thisroom).Objects[cc].Interaction;
 		for (cc = 0; cc < MAX_ROOM_REGIONS; cc++)
-			croom->intrRegion[cc] = *_GP(thisroom).Regions[cc].Interaction;
+			_G(croom)->intrRegion[cc] = *_GP(thisroom).Regions[cc].Interaction;
 	}
 
-	objs = &croom->obj[0];
+	_G(objs) = &_G(croom)->obj[0];
 
 	for (cc = 0; cc < MAX_ROOM_OBJECTS; cc++) {
 		// 64 bit: Using the id instead
-		// _G(scrObj)[cc].obj = &croom->obj[cc];
+		// _G(scrObj)[cc].obj = &_G(croom)->obj[cc];
 		_G(objectScriptObjNames)[cc].Free();
 	}
 
-	for (cc = 0; cc < croom->numobj; cc++) {
+	for (cc = 0; cc < _G(croom)->numobj; cc++) {
 		// export the object's script object
 		if (_GP(thisroom).Objects[cc].ScriptName.IsEmpty())
 			continue;
@@ -653,7 +647,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 		ccAddExternalDynamicObject(_GP(thisroom).Hotspots[cc].ScriptName, &_G(scrHotspot)[cc], &_GP(ccDynamicHotspot));
 	}
 
-	our_eip = 206;
+	_G(our_eip) = 206;
 	/*  THIS IS DONE IN THE EDITOR NOW
 	_GP(thisroom).BgFrames.IsPaletteShared[0] = 1;
 	for (dd = 1; dd < _GP(thisroom).BgFrameCount; dd++) {
@@ -668,7 +662,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 
 	update_polled_stuff_if_runtime();
 
-	our_eip = 210;
+	_G(our_eip) = 210;
 	if (IS_ANTIALIAS_SPRITES) {
 		// sometimes the palette has corrupt entries, which crash
 		// the create_rgb_table call
@@ -684,7 +678,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 		create_rgb_table(&rgb_table, palette, nullptr);
 		_G(rgb_map) = &rgb_table;
 	}
-	our_eip = 211;
+	_G(our_eip) = 211;
 	if (forchar != nullptr) {
 		// if it's not a Restore Game
 
@@ -716,60 +710,60 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	if (_G(debug_flags) & DBG_NOSCRIPT) ;
 	else if (_GP(thisroom).CompiledScript != nullptr) {
 		compile_room_script();
-		if (croom->tsdatasize > 0) {
-			if (croom->tsdatasize != _G(roominst)->globaldatasize)
+		if (_G(croom)->tsdatasize > 0) {
+			if (_G(croom)->tsdatasize != _G(roominst)->globaldatasize)
 				quit("room script data segment size has changed");
-			memcpy(&_G(roominst)->globaldata[0], croom->tsdata, croom->tsdatasize);
+			memcpy(&_G(roominst)->globaldata[0], _G(croom)->tsdata, _G(croom)->tsdatasize);
 		}
 	}
-	our_eip = 207;
+	_G(our_eip) = 207;
 	_GP(play).entered_edge = -1;
 
-	if ((new_room_x != SCR_NO_VALUE) && (forchar != nullptr)) {
-		forchar->x = new_room_x;
-		forchar->y = new_room_y;
+	if ((_G(new_room_x) != SCR_NO_VALUE) && (forchar != nullptr)) {
+		forchar->x = _G(new_room_x);
+		forchar->y = _G(new_room_y);
 
-		if (new_room_loop != SCR_NO_VALUE)
-			forchar->loop = new_room_loop;
+		if (_G(new_room_loop) != SCR_NO_VALUE)
+			forchar->loop = _G(new_room_loop);
 	}
-	new_room_x = SCR_NO_VALUE;
-	new_room_loop = SCR_NO_VALUE;
+	_G(new_room_x) = SCR_NO_VALUE;
+	_G(new_room_loop) = SCR_NO_VALUE;
 
-	if ((new_room_pos > 0) & (forchar != nullptr)) {
-		if (new_room_pos >= 4000) {
+	if ((_G(new_room_pos) > 0) & (forchar != nullptr)) {
+		if (_G(new_room_pos) >= 4000) {
 			_GP(play).entered_edge = 3;
 			forchar->y = _GP(thisroom).Edges.Top + get_fixed_pixel_size(1);
-			forchar->x = new_room_pos % 1000;
+			forchar->x = _G(new_room_pos) % 1000;
 			if (forchar->x == 0) forchar->x = _GP(thisroom).Width / 2;
 			if (forchar->x <= _GP(thisroom).Edges.Left)
 				forchar->x = _GP(thisroom).Edges.Left + 3;
 			if (forchar->x >= _GP(thisroom).Edges.Right)
 				forchar->x = _GP(thisroom).Edges.Right - 3;
 			forchar->loop = 0;
-		} else if (new_room_pos >= 3000) {
+		} else if (_G(new_room_pos) >= 3000) {
 			_GP(play).entered_edge = 2;
 			forchar->y = _GP(thisroom).Edges.Bottom - get_fixed_pixel_size(1);
-			forchar->x = new_room_pos % 1000;
+			forchar->x = _G(new_room_pos) % 1000;
 			if (forchar->x == 0) forchar->x = _GP(thisroom).Width / 2;
 			if (forchar->x <= _GP(thisroom).Edges.Left)
 				forchar->x = _GP(thisroom).Edges.Left + 3;
 			if (forchar->x >= _GP(thisroom).Edges.Right)
 				forchar->x = _GP(thisroom).Edges.Right - 3;
 			forchar->loop = 3;
-		} else if (new_room_pos >= 2000) {
+		} else if (_G(new_room_pos) >= 2000) {
 			_GP(play).entered_edge = 1;
 			forchar->x = _GP(thisroom).Edges.Right - get_fixed_pixel_size(1);
-			forchar->y = new_room_pos % 1000;
+			forchar->y = _G(new_room_pos) % 1000;
 			if (forchar->y == 0) forchar->y = _GP(thisroom).Height / 2;
 			if (forchar->y <= _GP(thisroom).Edges.Top)
 				forchar->y = _GP(thisroom).Edges.Top + 3;
 			if (forchar->y >= _GP(thisroom).Edges.Bottom)
 				forchar->y = _GP(thisroom).Edges.Bottom - 3;
 			forchar->loop = 1;
-		} else if (new_room_pos >= 1000) {
+		} else if (_G(new_room_pos) >= 1000) {
 			_GP(play).entered_edge = 0;
 			forchar->x = _GP(thisroom).Edges.Left + get_fixed_pixel_size(1);
-			forchar->y = new_room_pos % 1000;
+			forchar->y = _G(new_room_pos) % 1000;
 			if (forchar->y == 0) forchar->y = _GP(thisroom).Height / 2;
 			if (forchar->y <= _GP(thisroom).Edges.Top)
 				forchar->y = _GP(thisroom).Edges.Top + 3;
@@ -779,7 +773,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 		}
 		// if starts on un-walkable area
 		if (get_walkable_area_pixel(forchar->x, forchar->y) == 0) {
-			if (new_room_pos >= 3000) { // bottom or top of screen
+			if (_G(new_room_pos) >= 3000) { // bottom or top of screen
 				int tryleft = forchar->x - 1, tryright = forchar->x + 1;
 				while (1) {
 					if (get_walkable_area_pixel(tryleft, forchar->y) > 0) {
@@ -801,7 +795,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 					}
 					if (nowhere == 0) break; // no place to go, so leave him
 				}
-			} else if (new_room_pos >= 1000) { // left or right
+			} else if (_G(new_room_pos) >= 1000) { // left or right
 				int tryleft = forchar->y - 1, tryright = forchar->y + 1;
 				while (1) {
 					if (get_walkable_area_pixel(forchar->x, tryleft) > 0) {
@@ -825,7 +819,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 				}
 			}
 		}
-		new_room_pos = 0;
+		_G(new_room_pos) = 0;
 	}
 	if (forchar != nullptr) {
 		_GP(play).entered_at_x = forchar->x;
@@ -842,7 +836,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	if (_GP(thisroom).Options.StartupMusic > 0)
 		PlayMusicResetQueue(_GP(thisroom).Options.StartupMusic);
 
-	our_eip = 208;
+	_G(our_eip) = 208;
 	if (forchar != nullptr) {
 		if (_GP(thisroom).Options.PlayerCharOff == 0) {
 			forchar->on = 1;
@@ -862,7 +856,7 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	}
 	_G(color_map) = nullptr;
 
-	our_eip = 209;
+	_G(our_eip) = 209;
 	update_polled_stuff_if_runtime();
 	generate_light_table();
 	update_music_volume();
@@ -877,10 +871,10 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	}
 	init_room_drawdata();
 
-	our_eip = 212;
+	_G(our_eip) = 212;
 	invalidate_screen();
-	for (cc = 0; cc < croom->numobj; cc++) {
-		if (objs[cc].on == 2)
+	for (cc = 0; cc < _G(croom)->numobj; cc++) {
+		if (_G(objs)[cc].on == 2)
 			MergeObject(cc);
 	}
 	new_room_flags = 0;
@@ -892,11 +886,11 @@ void load_new_room(int newnum, CharacterInfo *forchar) {
 	if (_GP(game).color_depth > 1)
 		setpal();
 
-	our_eip = 220;
+	_G(our_eip) = 220;
 	update_polled_stuff_if_runtime();
-	debug_script_log("Now in room %d", displayed_room);
+	debug_script_log("Now in room %d", _G(displayed_room));
 	guis_need_update = 1;
-	pl_run_plugin_hooks(AGSE_ENTERROOM, displayed_room);
+	pl_run_plugin_hooks(AGSE_ENTERROOM, _G(displayed_room));
 	//  MoveToWalkableArea(_GP(game).playercharacter);
 	//  MSS_CHECK_ALL_BLOCKS;
 }
@@ -915,9 +909,9 @@ void new_room(int newnum, CharacterInfo *forchar) {
 	// player leaves screen event
 	run_room_event(8);
 	// Run the global OnRoomLeave event
-	run_on_event(GE_LEAVE_ROOM, RuntimeScriptValue().SetInt32(displayed_room));
+	run_on_event(GE_LEAVE_ROOM, RuntimeScriptValue().SetInt32(_G(displayed_room)));
 
-	pl_run_plugin_hooks(AGSE_LEAVEROOM, displayed_room);
+	pl_run_plugin_hooks(AGSE_LEAVEROOM, _G(displayed_room));
 
 	// update the new room number if it has been altered by OnLeave scripts
 	newnum = in_leaves_screen;
@@ -967,14 +961,14 @@ int find_highest_room_entered() {
 }
 
 void first_room_initialization() {
-	starting_room = displayed_room;
+	_G(starting_room) = _G(displayed_room);
 	set_loop_counter(0);
 	mouse_z_was = _G(mouse_z);
 }
 
 void check_new_room() {
 	// if they're in a new room, run Player Enters Screen and on_event(ENTER_ROOM)
-	if ((in_new_room > 0) & (in_new_room != 3)) {
+	if ((_G(in_new_room) > 0) & (_G(in_new_room) != 3)) {
 		EventHappened evh;
 		evh.type = EV_RUNEVBLOCK;
 		evh.data1 = EVB_ROOM;
@@ -982,12 +976,12 @@ void check_new_room() {
 		evh.data3 = 5;
 		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;
+		int newroom_was = _G(in_new_room);
+		_G(in_new_room) = 0;
 		_GP(play).disabled_user_interface ++;
 		process_event(&evh);
 		_GP(play).disabled_user_interface --;
-		in_new_room = newroom_was;
+		_G(in_new_room) = newroom_was;
 		//    setevent(EV_RUNEVBLOCK,EVB_ROOM,0,5);
 	}
 }
@@ -1040,8 +1034,8 @@ void on_background_frame_change() {
 }
 
 void croom_ptr_clear() {
-	croom = nullptr;
-	objs = nullptr;
+	_G(croom) = nullptr;
+	_G(objs) = nullptr;
 }
 
 
diff --git a/engines/ags/engine/ac/screen.cpp b/engines/ags/engine/ac/screen.cpp
index bdbc4788fb..0f8ac9094f 100644
--- a/engines/ags/engine/ac/screen.cpp
+++ b/engines/ags/engine/ac/screen.cpp
@@ -44,7 +44,7 @@ using namespace AGS::Engine;
 
 
 extern IGraphicsDriver *gfxDriver;
-extern AGSPlatformDriver *platform;
+
 
 void my_fade_in(PALETTE p, int speed) {
 	if (_GP(game).color_depth > 1) {
diff --git a/engines/ags/engine/ac/sprite.cpp b/engines/ags/engine/ac/sprite.cpp
index 3d46f0fac6..33226e9629 100644
--- a/engines/ags/engine/ac/sprite.cpp
+++ b/engines/ags/engine/ac/sprite.cpp
@@ -38,11 +38,10 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-
-extern int our_eip, eip_guinum, eip_guiobj;
+extern int eip_guinum, eip_guiobj;
 extern color palette[256];
 extern IGraphicsDriver *gfxDriver;
-extern AGSPlatformDriver *platform;
+
 
 void get_new_size_for_sprite(int ee, int ww, int hh, int &newwid, int &newhit) {
 	newwid = ww;
@@ -137,8 +136,8 @@ void initialize_sprite(int ee) {
 		_GP(game).SpriteInfos[ee].Height = 0;
 	} else {
 		// stretch sprites to correct resolution
-		int oldeip = our_eip;
-		our_eip = 4300;
+		int oldeip = _G(our_eip);
+		_G(our_eip) = 4300;
 
 		if (_GP(game).SpriteInfos[ee].Flags & SPF_HADALPHACHANNEL) {
 			// we stripped the alpha channel out last time, put
@@ -180,7 +179,7 @@ void initialize_sprite(int ee) {
 		pl_run_plugin_hooks(AGSE_SPRITELOAD, ee);
 		update_polled_stuff_if_runtime();
 
-		our_eip = oldeip;
+		_G(our_eip) = oldeip;
 	}
 }
 
diff --git a/engines/ags/engine/ac/sys_events.cpp b/engines/ags/engine/ac/sys_events.cpp
index 2ec07282ff..6bd8bded4a 100644
--- a/engines/ags/engine/ac/sys_events.cpp
+++ b/engines/ags/engine/ac/sys_events.cpp
@@ -41,7 +41,7 @@ using namespace AGS::Engine;
 
 extern volatile unsigned long globalTimerCounter;
 int pluginSimulatedClick;
-extern int displayed_room;
+
 extern char check_dynamic_sprites_at_exit;
 
 extern void domouse(int str);
@@ -182,7 +182,7 @@ int ags_getch() {
 	}
 
 	// Alt+X, abort (but only once game is loaded)
-	if ((gott == _GP(play).abort_key) && (displayed_room >= 0)) {
+	if ((gott == _GP(play).abort_key) && (_G(displayed_room) >= 0)) {
 		check_dynamic_sprites_at_exit = 0;
 		quit("!|");
 	}
@@ -203,7 +203,7 @@ void ags_clear_input_buffer() {
 
 void ags_wait_until_keypress() {
 	while (!SHOULD_QUIT && !ags_kbhit()) {
-		platform->YieldCPU();
+		_G(platform)->YieldCPU();
 	}
 
 	ags_getch();
diff --git a/engines/ags/engine/ac/system.cpp b/engines/ags/engine/ac/system.cpp
index c3770e21ce..6df3424766 100644
--- a/engines/ags/engine/ac/system.cpp
+++ b/engines/ags/engine/ac/system.cpp
@@ -53,10 +53,9 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern IGraphicsDriver *gfxDriver;
-extern volatile bool switched_away;
 
 bool System_HasInputFocus() {
-	return !switched_away;
+	return !_G(switched_away);
 }
 
 int System_GetColorDepth() {
diff --git a/engines/ags/engine/ac/walkablearea.cpp b/engines/ags/engine/ac/walkablearea.cpp
index 817c1d2058..64bdd3eb5d 100644
--- a/engines/ags/engine/ac/walkablearea.cpp
+++ b/engines/ags/engine/ac/walkablearea.cpp
@@ -40,10 +40,6 @@ using namespace AGS::Shared;
 
 
 
-extern int displayed_room;
-extern RoomStatus *croom;
-extern RoomObject *objs;
-
 Bitmap *walkareabackup = nullptr, *walkable_areas_temp = nullptr;
 
 void redo_walkable_areas() {
@@ -157,7 +153,7 @@ Bitmap *prepare_walkable_areas(int sourceChar) {
 	// them unwalkable
 	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 (_GP(game).chars[ww].room != _G(displayed_room)) continue;
 		if (ww == sourceChar) 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;
@@ -177,13 +173,13 @@ Bitmap *prepare_walkable_areas(int sourceChar) {
 
 	// check for any blocking objects in the room, and deal with them
 	// as well
-	for (ww = 0; ww < croom->numobj; ww++) {
-		if (objs[ww].on != 1) continue;
-		if ((objs[ww].flags & OBJF_SOLID) == 0)
+	for (ww = 0; ww < _G(croom)->numobj; ww++) {
+		if (_G(objs)[ww].on != 1) continue;
+		if ((_G(objs)[ww].flags & OBJF_SOLID) == 0)
 			continue;
-		if (room_to_mask_coord(objs[ww].y) >= walkable_areas_temp->GetHeight()) continue;
-		if (room_to_mask_coord(objs[ww].x) >= walkable_areas_temp->GetWidth()) continue;
-		if ((objs[ww].y < 0) || (objs[ww].x < 0)) continue;
+		if (room_to_mask_coord(_G(objs)[ww].y) >= walkable_areas_temp->GetHeight()) continue;
+		if (room_to_mask_coord(_G(objs)[ww].x) >= walkable_areas_temp->GetWidth()) continue;
+		if ((_G(objs)[ww].y < 0) || (_G(objs)[ww].x < 0)) continue;
 
 		int x1, y1, width, y2;
 		get_object_blocking_rect(ww, &x1, &y1, &width, &y2);
diff --git a/engines/ags/engine/debugging/debug.cpp b/engines/ags/engine/debugging/debug.cpp
index 13de177f31..b9d543f228 100644
--- a/engines/ags/engine/debugging/debug.cpp
+++ b/engines/ags/engine/debugging/debug.cpp
@@ -58,7 +58,7 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern char check_dynamic_sprites_at_exit;
-extern int displayed_room;
+
 extern char pexbuf[STD_BUFFER_SIZE];
 
 const char *OutputMsgBufID = "buffer";
@@ -88,10 +88,10 @@ PDebugOutput create_log_output(const String &name, const String &path = "", LogF
 		return _GP(DbgMgr).RegisterOutput(OutputSystemID, AGSPlatformDriver::GetDriver(), kDbgMsg_None);
 	} else if (name.CompareNoCase(OutputFileID) == 0) {
 		_GP(DebugLogFile).reset(new LogFile());
-		String logfile_path = !path.IsEmpty() ? path : String::FromFormat("%s/ags.log", platform->GetAppOutputDirectory());
+		String logfile_path = !path.IsEmpty() ? path : String::FromFormat("%s/ags.log", _G(platform)->GetAppOutputDirectory());
 		if (!_GP(DebugLogFile)->OpenFile(logfile_path, open_mode))
 			return nullptr;
-		platform->WriteStdOut("Logging to %s", logfile_path.GetCStr());
+		_G(platform)->WriteStdOut("Logging to %s", logfile_path.GetCStr());
 		auto dbgout = _GP(DbgMgr).RegisterOutput(OutputFileID, _GP(DebugLogFile).get(), kDbgMsg_None);
 		return dbgout;
 	} else if (name.CompareNoCase(OutputGameConsoleID) == 0) {
@@ -196,7 +196,7 @@ void apply_log_config(const ConfigTree &cfg, const String &log_id,
 void init_debug(const ConfigTree &cfg, bool stderr_only) {
 	// Register outputs
 	apply_debug_config(cfg);
-	platform->SetOutputToErr(stderr_only);
+	_G(platform)->SetOutputToErr(stderr_only);
 
 	if (stderr_only)
 		return;
@@ -285,7 +285,7 @@ void debug_script_print(const String &msg, MessageType mt) {
 		script_ref.Format("[%s%d]", scriptname.GetCStr(), _G(currentline));
 	}
 
-	Debug::Printf(kDbgGroup_Game, mt, "(room:%d)%s %s", displayed_room, script_ref.GetCStr(), msg.GetCStr());
+	Debug::Printf(kDbgGroup_Game, mt, "(room:%d)%s %s", _G(displayed_room), script_ref.GetCStr(), msg.GetCStr());
 }
 
 void debug_script_warn(const char *msg, ...) {
@@ -366,7 +366,7 @@ bool init_editor_debugging() {
 		// Wait for the editor to send the initial breakpoints
 		// and then its READY message
 		while (check_for_messages_from_editor() != 2) {
-			platform->Delay(10);
+			_G(platform)->Delay(10);
 		}
 
 		send_message_to_editor("START");
@@ -464,7 +464,7 @@ bool send_exception_to_editor(const char *qmsg) {
 		return false;
 
 	while ((check_for_messages_from_editor() == 0) && (_G(want_exit) == 0)) {
-		platform->Delay(10);
+		_G(platform)->Delay(10);
 	}
 #endif
 	return true;
@@ -482,7 +482,7 @@ void break_into_debugger() {
 
 	while (_G(game_paused_in_debugger)) {
 		update_polled_stuff_if_runtime();
-		platform->YieldCPU();
+		_G(platform)->YieldCPU();
 	}
 
 #endif
diff --git a/engines/ags/engine/debugging/debug_log.h b/engines/ags/engine/debugging/debug_log.h
index 6d20839f25..37744f9fed 100644
--- a/engines/ags/engine/debugging/debug_log.h
+++ b/engines/ags/engine/debugging/debug_log.h
@@ -49,7 +49,7 @@ bool init_editor_debugging();
 // allow LShift to single-step,  RShift to pause flow
 void scriptDebugHook(ccInstance *ccinst, int linenum);
 
-extern AGSPlatformDriver *platform;
+
 
 } // namespace AGS3
 
diff --git a/engines/ags/engine/debugging/filebasedagsdebugger.cpp b/engines/ags/engine/debugging/filebasedagsdebugger.cpp
index 501998aa2a..5300cf622d 100644
--- a/engines/ags/engine/debugging/filebasedagsdebugger.cpp
+++ b/engines/ags/engine/debugging/filebasedagsdebugger.cpp
@@ -26,6 +26,7 @@
 #include "ags/shared/util/textstreamwriter.h"
 #include "ags/shared/util/wgt2allg.h"              // exists()
 #include "ags/engine/platform/base/agsplatformdriver.h"
+#include "ags/globals.h"
 #include "common/system.h"
 #include "common/savefile.h"
 
@@ -60,7 +61,7 @@ void FileBasedAGSDebugger::Shutdown() {
 
 bool FileBasedAGSDebugger::SendMessageToEditor(const char *message) {
 	while (exists(SENT_MESSAGE_FILE_NAME)) {
-		platform->YieldCPU();
+		_G(platform)->YieldCPU();
 	}
 
 	Stream *out = Shared::File::CreateFile(SENT_MESSAGE_FILE_NAME);
diff --git a/engines/ags/engine/device/mousew32.cpp b/engines/ags/engine/device/mousew32.cpp
index 6c96f935f8..ec2fa2d5c8 100644
--- a/engines/ags/engine/device/mousew32.cpp
+++ b/engines/ags/engine/device/mousew32.cpp
@@ -71,7 +71,6 @@ const int NONE = -1, LEFT = 0, RIGHT = 1, MIDDLE = 2;
 extern char lib_file_name[13];
 extern char alpha_blend_cursor;
 extern color palette[256];
-extern volatile bool switched_away;
 
 namespace Mouse {
 
@@ -117,7 +116,7 @@ void mgetgraphpos() {
 		return;
 	}
 
-	if (!switched_away && Mouse::ControlEnabled) {
+	if (!_G(switched_away) && Mouse::ControlEnabled) {
 		// Control mouse movement by querying mouse mickeys (movement deltas)
 		// and applying them to saved mouse coordinates.
 		int mickey_x, mickey_y;
@@ -308,12 +307,12 @@ bool Mouse::IsLockedToWindow() {
 
 bool Mouse::TryLockToWindow() {
 	if (!LockedToWindow)
-		LockedToWindow = platform->LockMouseToWindow();
+		LockedToWindow = _G(platform)->LockMouseToWindow();
 	return LockedToWindow;
 }
 
 void Mouse::UnlockFromWindow() {
-	platform->UnlockMouse();
+	_G(platform)->UnlockMouse();
 	LockedToWindow = false;
 }
 
diff --git a/engines/ags/engine/font/fonts_engine.cpp b/engines/ags/engine/font/fonts_engine.cpp
index 5e7c3871ad..54faf9dda4 100644
--- a/engines/ags/engine/font/fonts_engine.cpp
+++ b/engines/ags/engine/font/fonts_engine.cpp
@@ -28,22 +28,20 @@
 
 #include "ags/lib/alfont/alfont.h"
 #include "ags/shared/ac/gamesetupstruct.h"
+#include "ags/globals.h"
 
 namespace AGS3 {
 
-extern int our_eip;
-
-
 //=============================================================================
 // Engine-specific implementation split out of acfonts.cpp
 //=============================================================================
 
 void set_our_eip(int eip) {
-	our_eip = eip;
+	_G(our_eip) = eip;
 }
 
 int get_our_eip() {
-	return our_eip;
+	return _G(our_eip);
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index e6df98a9c0..9e6b8b641e 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -298,7 +298,7 @@ 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 (_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.");
+		_G(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
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 98d2d1c213..7bd9074781 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -79,9 +79,6 @@ extern AGS::Engine::IGraphicsDriver *gfxDriver;
 extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
 extern Bitmap *raw_saved_screen;
 
-extern RoomStatus *croom;
-
-
 namespace AGS {
 namespace Engine {
 
@@ -492,8 +489,8 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 	update_polled_stuff_if_runtime();
 
 	// load the room the game was saved in
-	if (displayed_room >= 0)
-		load_new_room(displayed_room, nullptr);
+	if (_G(displayed_room) >= 0)
+		load_new_room(_G(displayed_room), nullptr);
 
 	update_polled_stuff_if_runtime();
 
@@ -515,14 +512,14 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 
 	update_polled_stuff_if_runtime();
 
-	if (displayed_room >= 0) {
+	if (_G(displayed_room) >= 0) {
 		for (int i = 0; i < MAX_ROOM_BGFRAMES; ++i) {
 			if (r_data.RoomBkgScene[i]) {
 				_GP(thisroom).BgFrames[i].Graphic = r_data.RoomBkgScene[i];
 			}
 		}
 
-		in_new_room = 3; // don't run "enters screen" events
+		_G(in_new_room) = 3; // don't run "enters screen" events
 		// now that room has loaded, copy saved light levels in
 		for (size_t i = 0; i < MAX_ROOM_REGIONS; ++i) {
 			_GP(thisroom).Regions[i].Light = r_data.RoomLightLevels[i];
@@ -618,7 +615,7 @@ HSaveError DoAfterRestore(const PreservedParams &pp, const RestoredData &r_data)
 
 	pl_run_plugin_hooks(AGSE_POSTRESTOREGAME, 0);
 
-	if (displayed_room < 0) {
+	if (_G(displayed_room) < 0) {
 		// the restart point, no room was loaded
 		load_new_room(playerchar->room, playerchar);
 		playerchar->prevroom = -1;
@@ -729,14 +726,14 @@ void DoBeforeSave() {
 			_GP(play).cur_music_number = -1;
 	}
 
-	if (displayed_room >= 0) {
+	if (_G(displayed_room) >= 0) {
 		// update the current room script's data segment copy
 		if (_G(roominst))
 			save_room_data_segment();
 
 		// Update the saved interaction variable values
 		for (size_t i = 0; i < _GP(thisroom).LocalVariables.size() && i < (size_t)MAX_GLOBAL_VARIABLES; ++i)
-			croom->interactionVariableValues[i] = _GP(thisroom).LocalVariables[i].Value;
+			_G(croom)->interactionVariableValues[i] = _GP(thisroom).LocalVariables[i].Value;
 	}
 }
 
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 4cbc5cc3e2..9e60c68627 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -210,7 +210,7 @@ HSaveError WriteGameState(PStream out) {
 	// Game state
 	_GP(play).WriteForSavegame(out.get());
 	// Other dynamic values
-	out->WriteInt32(frames_per_second);
+	out->WriteInt32(_G(frames_per_second));
 	out->WriteInt32(loopcounter);
 	out->WriteInt32(ifacepopped);
 	out->WriteInt32(game_paused);
@@ -884,8 +884,8 @@ HSaveError ReadRoomStates(PStream in, int32_t cmp_ver, const PreservedParams &pp
 }
 
 HSaveError WriteThisRoom(PStream out) {
-	out->WriteInt32(displayed_room);
-	if (displayed_room < 0)
+	out->WriteInt32(_G(displayed_room));
+	if (_G(displayed_room) < 0)
 		return HSaveError::None();
 
 	// modified room backgrounds
@@ -918,7 +918,7 @@ HSaveError WriteThisRoom(PStream out) {
 	out->WriteInt32(_GP(thisroom).Options.MusicVolume);
 
 	// persistent room's indicator
-	const bool persist = displayed_room < MAX_ROOMS;
+	const bool persist = _G(displayed_room) < MAX_ROOMS;
 	out->WriteBool(persist);
 	// write the current troom state, in case they save in temporary room
 	if (!persist)
@@ -928,8 +928,8 @@ HSaveError WriteThisRoom(PStream out) {
 
 HSaveError ReadThisRoom(PStream in, int32_t cmp_ver, const PreservedParams &pp, RestoredData &r_data) {
 	HSaveError err;
-	displayed_room = in->ReadInt32();
-	if (displayed_room < 0)
+	_G(displayed_room) = in->ReadInt32();
+	if (_G(displayed_room) < 0)
 		return err;
 
 	// modified room backgrounds
diff --git a/engines/ags/engine/gfx/ali3dscummvm.cpp b/engines/ags/engine/gfx/ali3dscummvm.cpp
index fe9253c6a1..93417fe402 100644
--- a/engines/ags/engine/gfx/ali3dscummvm.cpp
+++ b/engines/ags/engine/gfx/ali3dscummvm.cpp
@@ -37,6 +37,7 @@
 #include "ags/engine/ac/timer.h"
 #include "ags/lib/allegro/color.h"
 #include "ags/lib/std/algorithm.h"
+#include "ags/globals.h"
 #include "ags/ags.h"
 
 namespace AGS3 {
@@ -702,7 +703,7 @@ void ALScummVMGraphicsDriver::BoxOutEffect(bool blackingOut, int speed, int dela
 			if (_pollingCallback)
 				_pollingCallback();
 
-			platform->Delay(delay);
+			_G(platform)->Delay(delay);
 		}
 		delete bmp_buff;
 		SetMemoryBackBuffer(bmp_orig);
diff --git a/engines/ags/engine/main/config.cpp b/engines/ags/engine/main/config.cpp
index 698441097f..4c1672beef 100644
--- a/engines/ags/engine/main/config.cpp
+++ b/engines/ags/engine/main/config.cpp
@@ -224,12 +224,12 @@ String find_default_cfg_file(const char *alt_cfg_file) {
 }
 
 String find_user_global_cfg_file() {
-	String parent_dir = PathOrCurDir(platform->GetUserGlobalConfigDirectory());
+	String parent_dir = PathOrCurDir(_G(platform)->GetUserGlobalConfigDirectory());
 	return String::FromFormat("%s/%s", parent_dir.GetCStr(), DefaultConfigFileName.GetCStr());
 }
 
 String find_user_cfg_file() {
-	String parent_dir = MakeSpecialSubDir(PathOrCurDir(platform->GetUserConfigDirectory()));
+	String parent_dir = MakeSpecialSubDir(PathOrCurDir(_G(platform)->GetUserConfigDirectory()));
 	return String::FromFormat("%s/%s", parent_dir.GetCStr(), DefaultConfigFileName.GetCStr());
 }
 
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index 1067ce65c5..2509018070 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -84,11 +84,7 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern char check_dynamic_sprites_at_exit;
-extern int our_eip;
-extern int proper_exit;
 extern char pexbuf[STD_BUFFER_SIZE];
-
-extern int displayed_room;
 extern int eip_guinum;
 extern int eip_guiobj;
 extern SpeechLipSyncLine *splipsync;
@@ -107,13 +103,13 @@ extern IDriverDependantBitmap **guibgbmp;
 bool engine_init_allegro() {
 	Debug::Printf(kDbgMsg_Info, "Initializing allegro");
 
-	our_eip = -199;
+	_G(our_eip) = -199;
 	// Initialize allegro
 	set_uformat(U_ASCII);
 	if (install_allegro()) {
 		const char *al_err = get_allegro_error();
-		const char *user_hint = platform->GetAllegroFailUserHint();
-		platform->DisplayAlert("Unable to initialize Allegro system driver.\n%s\n\n%s",
+		const char *user_hint = _G(platform)->GetAllegroFailUserHint();
+		_G(platform)->DisplayAlert("Unable to initialize Allegro system driver.\n%s\n\n%s",
 		                       al_err[0] ? al_err : "Allegro library provided no further information on the problem.",
 		                       user_hint);
 		return false;
@@ -131,11 +127,11 @@ void engine_setup_allegro() {
 void engine_setup_window() {
 	Debug::Printf(kDbgMsg_Info, "Setting up window");
 
-	our_eip = -198;
+	_G(our_eip) = -198;
 	//set_window_title("Adventure Game Studio");
-	our_eip = -197;
+	_G(our_eip) = -197;
 
-	platform->SetGameWindowIcon();
+	_G(platform)->SetGameWindowIcon();
 }
 
 // Starts up setup application, if capable.
@@ -153,11 +149,11 @@ bool engine_run_setup(const String &exe_path, ConfigTree &cfg, int &app_res) {
 		Debug::Printf(kDbgMsg_Info, "Running Setup");
 
 		ConfigTree cfg_out;
-		SetupReturnValue res = platform->RunSetup(cfg, cfg_out);
+		SetupReturnValue res = _G(platform)->RunSetup(cfg, cfg_out);
 		if (res != kSetup_Cancel) {
 			if (!IniUtil::Merge(cfg_file, cfg_out)) {
-				platform->DisplayAlert("Unable to write to the configuration file (error code 0x%08X).\n%s",
-				                       platform->GetLastSystemError(), platform->GetDiskWriteAccessTroubleshootingText());
+				_G(platform)->DisplayAlert("Unable to write to the configuration file (error code 0x%08X).\n%s",
+				                       _G(platform)->GetLastSystemError(), _G(platform)->GetDiskWriteAccessTroubleshootingText());
 			}
 		}
 		if (res != kSetup_RunGame)
@@ -283,7 +279,7 @@ bool engine_try_init_gamedata(String gamepak_path) {
 	// Search for an available game package in the known locations
 	AssetError err = AssetManager::SetDataFile(gamepak_path);
 	if (err != kAssetNoError) {
-		platform->DisplayAlert("ERROR: The game data is missing, is of unsupported format or corrupt.\nFile: '%s'", gamepak_path.GetCStr());
+		_G(platform)->DisplayAlert("ERROR: The game data is missing, is of unsupported format or corrupt.\nFile: '%s'", gamepak_path.GetCStr());
 		return false;
 	}
 	return true;
@@ -313,7 +309,7 @@ void engine_locate_speech_pak() {
 		if (!speech_filepath.IsEmpty()) {
 			Debug::Printf("Initializing speech vox");
 			if (AssetManager::SetDataFile(speech_filepath) != Shared::kAssetNoError) {
-				platform->DisplayAlert("Unable to read voice pack, file could be corrupted or of unknown format.\nSpeech voice-over will be disabled.");
+				_G(platform)->DisplayAlert("Unable to read voice pack, file could be corrupted or of unknown format.\nSpeech voice-over will be disabled.");
 				AssetManager::SetDataFile(_GP(ResPaths).GamePak.Path); // switch back to the main data pack
 				return;
 			}
@@ -363,7 +359,7 @@ void engine_locate_audio_pak() {
 			_GP(ResPaths).AudioPak.Name = music_file;
 			_GP(ResPaths).AudioPak.Path = music_filepath;
 		} else {
-			platform->DisplayAlert("Unable to initialize digital audio pack '%s', file could be corrupt or of unsupported format.",
+			_G(platform)->DisplayAlert("Unable to initialize digital audio pack '%s', file could be corrupt or of unsupported format.",
 			                       music_file.GetCStr());
 		}
 	}
@@ -393,7 +389,7 @@ void engine_init_audio() {
 		audio_core_init(); // audio core system
 	}
 #endif
-	our_eip = -181;
+	_G(our_eip) = -181;
 
 	if (_GP(usetup).audio_backend == 0) {
 		// all audio is disabled
@@ -405,7 +401,7 @@ void engine_init_audio() {
 
 void engine_init_debug() {
 	if ((_G(debug_flags) & (~DBG_DEBUGMODE)) > 0) {
-		platform->DisplayAlert("Engine debugging enabled.\n"
+		_G(platform)->DisplayAlert("Engine debugging enabled.\n"
 		                       "\nNOTE: You have selected to enable one or more engine debugging options.\n"
 		                       "These options cause many parts of the game to behave abnormally, and you\n"
 		                       "may not see the game as you are used to it. The point is to test whether\n"
@@ -414,22 +410,6 @@ void engine_init_debug() {
 	}
 }
 
-void atexit_handler() {
-	if (proper_exit == 0) {
-		platform->DisplayAlert("Error: the program has exited without requesting it.\n"
-		                       "Program pointer: %+03d  (write this number down), ACI version %s\n"
-		                       "If you see a list of numbers above, please write them down and contact\n"
-		                       "developers. Otherwise, note down any other information displayed.",
-		                       our_eip, _G(EngineVersion).LongString.GetCStr());
-	}
-}
-
-void engine_init_exit_handler() {
-	Debug::Printf(kDbgMsg_Info, "Install exit handler");
-
-	atexit(atexit_handler);
-}
-
 void engine_init_rand() {
 	_GP(play).randseed = g_system->getMillis();
 	::AGS::g_vm->setRandomNumberSeed(_GP(play).randseed);
@@ -442,16 +422,16 @@ void engine_init_pathfinder() {
 void engine_pre_init_gfx() {
 	//Debug::Printf("Initialize gfx");
 
-	//platform->InitialiseAbufAtStartup();
+	//_G(platform)->InitialiseAbufAtStartup();
 }
 
 int engine_load_game_data() {
 	Debug::Printf("Load game data");
-	our_eip = -17;
+	_G(our_eip) = -17;
 	HError err = load_game_file();
 	if (!err) {
-		proper_exit = 1;
-		platform->FinishedUsingGraphicsMode();
+		_G(proper_exit) = 1;
+		_G(platform)->FinishedUsingGraphicsMode();
 		display_game_file_error(err);
 		return EXIT_ERROR;
 	}
@@ -460,14 +440,14 @@ int engine_load_game_data() {
 
 int engine_check_register_game() {
 	if (_G(justRegisterGame)) {
-		platform->RegisterGameWithGameExplorer();
-		proper_exit = 1;
+		_G(platform)->RegisterGameWithGameExplorer();
+		_G(proper_exit) = 1;
 		return EXIT_NORMAL;
 	}
 
 	if (_G(justUnRegisterGame)) {
-		platform->UnRegisterGameWithGameExplorer();
-		proper_exit = 1;
+		_G(platform)->UnRegisterGameWithGameExplorer();
+		_G(proper_exit) = 1;
 		return EXIT_NORMAL;
 	}
 
@@ -475,7 +455,7 @@ int engine_check_register_game() {
 }
 
 void engine_init_title() {
-	our_eip = -91;
+	_G(our_eip) = -91;
 	::AGS::g_vm->set_window_title(_GP(game).gamename);
 	Debug::Printf(kDbgMsg_Info, "Game title: '%s'", _GP(game).gamename);
 }
@@ -530,10 +510,10 @@ int check_write_access() {
 	return true;
 #else
 
-	if (platform->GetDiskFreeSpaceMB() < 2)
+	if (_G(platform)->GetDiskFreeSpaceMB() < 2)
 		return 0;
 
-	our_eip = -1895;
+	_G(our_eip) = -1895;
 
 	// The Save Game Dir is the only place that we should write to
 	String svg_dir = get_save_game_directory();
@@ -553,12 +533,12 @@ int check_write_access() {
 		return 0;
 #endif // AGS_PLATFORM_OS_ANDROID
 
-	our_eip = -1896;
+	_G(our_eip) = -1896;
 
 	temp_s->Write("just to test the drive free space", 30);
 	delete temp_s;
 
-	our_eip = -1897;
+	_G(our_eip) = -1897;
 
 	if (::remove(tempPath))
 		return 0;
@@ -571,8 +551,8 @@ int engine_check_disk_space() {
 	Debug::Printf(kDbgMsg_Info, "Checking for disk space");
 
 	if (check_write_access() == 0) {
-		platform->DisplayAlert("Unable to write in the savegame directory.\n%s", platform->GetDiskWriteAccessTroubleshootingText());
-		proper_exit = 1;
+		_G(platform)->DisplayAlert("Unable to write in the savegame directory.\n%s", _G(platform)->GetDiskWriteAccessTroubleshootingText());
+		_G(proper_exit) = 1;
 		return EXIT_ERROR;
 	}
 
@@ -581,8 +561,8 @@ 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.");
-		proper_exit = 1;
+		_G(platform)->DisplayAlert("No game fonts found. At least one font is required to run the game.");
+		_G(proper_exit) = 1;
 		return EXIT_ERROR;
 	}
 
@@ -616,7 +596,7 @@ void show_preload() {
 		gfxDriver->DestroyDDB(ddb);
 		delete splashsc;
 		delete tsc;
-		platform->Delay(500);
+		_G(platform)->Delay(500);
 	}
 }
 
@@ -625,10 +605,10 @@ int engine_init_sprites() {
 
 	HError err = _GP(spriteset).InitFile(SpriteCache::DefaultSpriteFileName, SpriteCache::DefaultSpriteIndexName);
 	if (!err) {
-		platform->FinishedUsingGraphicsMode();
+		_G(platform)->FinishedUsingGraphicsMode();
 		allegro_exit();
-		proper_exit = 1;
-		platform->DisplayAlert("Could not load sprite set file %s\n%s",
+		_G(proper_exit) = 1;
+		_G(platform)->DisplayAlert("Could not load sprite set file %s\n%s",
 		                       SpriteCache::DefaultSpriteFileName,
 		                       err->FullMessage().GetCStr());
 		return EXIT_ERROR;
@@ -638,7 +618,7 @@ int engine_init_sprites() {
 }
 
 void engine_init_game_settings() {
-	our_eip = -7;
+	_G(our_eip) = -7;
 	Debug::Printf("Initialize game settings");
 
 	int ee;
@@ -675,7 +655,7 @@ void engine_init_game_settings() {
 	dummyguicontrol.guin = -1;
 	dummyguicontrol.objn = -1;*/
 
-	our_eip = -6;
+	_G(our_eip) = -6;
 	//  _GP(game).chars[0].talkview=4;
 	//init_language_text(_GP(game).langcodes[0]);
 
@@ -718,7 +698,7 @@ void engine_init_game_settings() {
 		guibgbmp[ee] = nullptr;
 	}
 
-	our_eip = -5;
+	_G(our_eip) = -5;
 	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;
@@ -879,10 +859,10 @@ void engine_init_game_settings() {
 		init_translation(_GP(usetup).translation, "", true);
 
 	update_invorder();
-	displayed_room = -10;
+	_G(displayed_room) = -10;
 
 	_G(currentcursor) = 0;
-	our_eip = -4;
+	_G(our_eip) = -4;
 	_G(mousey) = 100; // stop icon bar popping up
 
 	// We use same variable to read config and be used at runtime for now,
@@ -898,7 +878,7 @@ void engine_setup_scsystem_auxiliary() {
 	if (_GP(usetup).override_script_os >= 0) {
 		_GP(scsystem).os = _GP(usetup).override_script_os;
 	} else {
-		_GP(scsystem).os = platform->GetSystemOSID();
+		_GP(scsystem).os = _G(platform)->GetSystemOSID();
 	}
 }
 
@@ -975,7 +955,7 @@ HError define_gamedata_location_checkall(const String &exe_path) {
 bool define_gamedata_location(const String &exe_path) {
 	HError err = define_gamedata_location_checkall(exe_path);
 	if (!err) {
-		platform->DisplayAlert("ERROR: Unable to determine game data.\n%s", err->FullMessage().GetCStr());
+		_G(platform)->DisplayAlert("ERROR: Unable to determine game data.\n%s", err->FullMessage().GetCStr());
 		main_print_help();
 		return false;
 	}
@@ -1122,7 +1102,7 @@ static void engine_print_info(const std::set<String> &keys, const String &exe_pa
 	}
 	String full;
 	IniUtil::WriteToString(full, data);
-	platform->WriteStdOut("%s", full.GetCStr());
+	_G(platform)->WriteStdOut("%s", full.GetCStr());
 }
 
 // TODO: this function is still a big mess, engine/system-related initialization
@@ -1165,53 +1145,51 @@ int initialize_engine(const ConfigTree &startup_opts) {
 	engine_setup_allegro();
 	engine_force_window();
 
-	our_eip = -190;
+	_G(our_eip) = -190;
 
 	//-----------------------------------------------------
 	// Init data paths and other directories, locate general data files
 	engine_init_directories();
 
-	our_eip = -191;
+	_G(our_eip) = -191;
 
 	engine_locate_speech_pak();
 
-	our_eip = -192;
+	_G(our_eip) = -192;
 
 	engine_locate_audio_pak();
 
-	our_eip = -193;
+	_G(our_eip) = -193;
 
 	//-----------------------------------------------------
 	// Begin setting up systems
 	engine_setup_window();
 
-	our_eip = -194;
+	_G(our_eip) = -194;
 
 	engine_init_fonts();
 
-	our_eip = -195;
+	_G(our_eip) = -195;
 
 	engine_init_keyboard();
 
-	our_eip = -196;
+	_G(our_eip) = -196;
 
 	engine_init_mouse();
 
-	our_eip = -197;
+	_G(our_eip) = -197;
 
 	engine_init_timer();
 
-	our_eip = -198;
+	_G(our_eip) = -198;
 
 	engine_init_audio();
 
-	our_eip = -199;
+	_G(our_eip) = -199;
 
 	engine_init_debug();
 
-	our_eip = -10;
-
-	engine_init_exit_handler();
+	_G(our_eip) = -10;
 
 	engine_init_rand();
 
@@ -1219,8 +1197,8 @@ int initialize_engine(const ConfigTree &startup_opts) {
 
 	set_game_speed(40);
 
-	our_eip = -20;
-	our_eip = -19;
+	_G(our_eip) = -20;
+	_G(our_eip) = -19;
 
 	int res = engine_load_game_data();
 	if (res != 0)
@@ -1232,7 +1210,7 @@ int initialize_engine(const ConfigTree &startup_opts) {
 
 	engine_init_title();
 
-	our_eip = -189;
+	_G(our_eip) = -189;
 
 	res = engine_check_disk_space();
 	if (res != 0)
@@ -1245,7 +1223,7 @@ int initialize_engine(const ConfigTree &startup_opts) {
 	if (res != 0)
 		return res;
 
-	our_eip = -179;
+	_G(our_eip) = -179;
 
 	engine_init_resolution_settings(_GP(game).GetGameRes());
 
diff --git a/engines/ags/engine/main/engine_setup.cpp b/engines/ags/engine/main/engine_setup.cpp
index f4cd318877..0c12c1cec3 100644
--- a/engines/ags/engine/main/engine_setup.cpp
+++ b/engines/ags/engine/main/engine_setup.cpp
@@ -316,7 +316,7 @@ void engine_post_gfxmode_setup(const Size &init_desktop) {
 	// "windowed" flag to be specified. Find out whether this function
 	// has anything to do with graphics mode at all. It is quite possible
 	// that we may split it into two functions, or remove parameter.
-	platform->PostAllegroInit(_GP(scsystem).windowed != 0);
+	_G(platform)->PostAllegroInit(_GP(scsystem).windowed != 0);
 
 	video_on_gfxmode_changed();
 	invalidate_screen();
diff --git a/engines/ags/engine/main/game_file.cpp b/engines/ags/engine/main/game_file.cpp
index f25f59a9fc..def0418591 100644
--- a/engines/ags/engine/main/game_file.cpp
+++ b/engines/ags/engine/main/game_file.cpp
@@ -61,7 +61,7 @@ using namespace AGS::Engine;
 
 extern int ifacepopped;
 extern DialogTopic *dialog;
-extern AGSPlatformDriver *platform;
+
 
 // Test if engine supports extended capabilities required to run the game
 bool test_game_caps(const std::set<String> &caps, std::set<String> &failed_caps) {
@@ -149,7 +149,7 @@ HError load_game_file() {
 }
 
 void display_game_file_error(HError err) {
-	platform->DisplayAlert("Loading game failed with error:\n%s.\n\nThe game files may be incomplete, corrupt or from unsupported version of AGS.",
+	_G(platform)->DisplayAlert("Loading game failed with error:\n%s.\n\nThe game files may be incomplete, corrupt or from unsupported version of AGS.",
 		err->FullMessage().GetCStr());
 }
 
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index b0db30fd29..e6ee93e992 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -75,9 +75,6 @@ using namespace AGS::Shared;
 
 extern int mouse_on_iface;   // mouse cursor is over this interface
 extern int ifacepopped;
-extern int proper_exit, our_eip;
-extern int displayed_room, starting_room, in_new_room, new_room_was;
-
 
 extern int game_paused;
 extern int getloctype_index;
@@ -86,9 +83,7 @@ extern int in_leaves_screen;
 extern CharacterInfo *playerchar;
 extern int mouse_ifacebut_xoffs, mouse_ifacebut_yoffs;
 extern int cur_mode;
-extern RoomObject *objs;
 extern char noWalkBehindsAtAll;
-extern RoomStatus *croom;
 extern CharacterExtras *charextra;
 
 extern int cur_mode, cur_cursor;
@@ -119,12 +114,12 @@ static unsigned int lastcounter = 0;
 
 static void ProperExit() {
 	_G(want_exit) = 0;
-	proper_exit = 1;
+	_G(proper_exit) = true;
 	quit("||exit!");
 }
 
 static void game_loop_check_problems_at_start() {
-	if ((in_enters_screen != 0) & (displayed_room == starting_room))
+	if ((in_enters_screen != 0) & (_G(displayed_room) == _G(starting_room)))
 		quit("!A text script run in the Player Enters Screen event caused the\n"
 			"screen to be updated. If you need to use Wait(), do so in After Fadein");
 	if ((in_enters_screen != 0) && (done_es_error == 0)) {
@@ -136,7 +131,7 @@ static void game_loop_check_problems_at_start() {
 }
 
 static void game_loop_check_new_room() {
-	if (in_new_room == 0) {
+	if (_G(in_new_room) == 0) {
 		// Run the room and game script repeatedly_execute
 		run_function_on_non_blocking_thread(&_GP(repExecAlways));
 		setevent(EV_TEXTSCRIPT, TS_REPEAT);
@@ -148,7 +143,7 @@ static void game_loop_check_new_room() {
 }
 
 static void game_loop_do_late_update() {
-	if (in_new_room == 0) {
+	if (_G(in_new_room) == 0) {
 		// Run the room and game script late_repeatedly_execute
 		run_function_on_non_blocking_thread(&_GP(lateRepExecAlways));
 	}
@@ -163,7 +158,7 @@ static int game_loop_check_ground_level_interactions() {
 
 		// check current region
 		int onRegion = GetRegionIDAtRoom(playerchar->x, playerchar->y);
-		int inRoom = displayed_room;
+		int inRoom = _G(displayed_room);
 
 		if (onRegion != _GP(play).player_on_region) {
 			// we need to save this and set _GP(play).player_on_region
@@ -182,7 +177,7 @@ static int game_loop_check_ground_level_interactions() {
 			RunRegionInteraction(_GP(play).player_on_region, 0);
 
 		// one of the region interactions sent us to another room
-		if (inRoom != displayed_room) {
+		if (inRoom != _G(displayed_room)) {
 			check_new_room();
 		}
 
@@ -405,7 +400,7 @@ static void check_keyboard_controls() {
 
 	if ((kgn == eAGSKeyCodeCtrlE) && (_G(display_fps) == kFPS_Forced)) {
 		// if --fps paramter is used, Ctrl+E will max out frame rate
-		setTimerFps(isTimerFpsMaxed() ? frames_per_second : 1000);
+		setTimerFps(isTimerFpsMaxed() ? _G(frames_per_second) : 1000);
 		return;
 	}
 
@@ -415,28 +410,28 @@ static void check_keyboard_controls() {
 		int ff;
 		// MACPORT FIX 9/6/5: added last %s
 		sprintf(infobuf, "In room %d %s[Player at %d, %d (view %d, loop %d, frame %d)%s%s%s",
-			displayed_room, (noWalkBehindsAtAll ? "(has no walk-behinds)" : ""), playerchar->x, playerchar->y,
+			_G(displayed_room), (noWalkBehindsAtAll ? "(has no walk-behinds)" : ""), playerchar->x, playerchar->y,
 			playerchar->view + 1, playerchar->loop, playerchar->frame,
 			(IsGamePaused() == 0) ? "" : "[Game paused.",
 			(_GP(play).ground_level_areas_disabled == 0) ? "" : "[Ground areas disabled.",
 			(IsInterfaceEnabled() == 0) ? "[Game in Wait state" : "");
-		for (ff = 0; ff < croom->numobj; ff++) {
+		for (ff = 0; ff < _G(croom)->numobj; ff++) {
 			if (ff >= 8) break; // buffer not big enough for more than 7
 			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,
-				(_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);
+				ff, _G(objs)[ff].x, _G(objs)[ff].y,
+				(_GP(spriteset)[_G(objs)[ff].num] != nullptr) ? _GP(game).SpriteInfos[_G(objs)[ff].num].Width : 0,
+				(_GP(spriteset)[_G(objs)[ff].num] != nullptr) ? _GP(game).SpriteInfos[_G(objs)[ff].num].Height : 0,
+				_G(objs)[ff].on,
+				(_G(objs)[ff].moving > 0) ? "yes" : "no", _G(objs)[ff].cycling,
+				_G(objs)[ff].num, _G(objs)[ff].transparent,
+				((_G(objs)[ff].flags & OBJF_NOINTERACT) != 0) ? 0 : 1);
 		}
 		Display(infobuf);
 		int chd = _GP(game).playercharacter;
 		char bigbuffer[STD_BUFFER_SIZE] = "CHARACTERS IN THIS ROOM:[";
 		for (ff = 0; ff < _GP(game).numcharacters; ff++) {
-			if (_GP(game).chars[ff].room != displayed_room) continue;
+			if (_GP(game).chars[ff].room != _G(displayed_room)) continue;
 			if (strlen(bigbuffer) > 430) {
 				strcat(bigbuffer, "and more...");
 				Display(bigbuffer);
@@ -535,7 +530,7 @@ static void check_keyboard_controls() {
 
 // check_controls: checks mouse & keyboard interface
 static void check_controls() {
-	our_eip = 1007;
+	_G(our_eip) = 1007;
 
 	check_mouse_controls();
 	check_keyboard_controls();
@@ -543,7 +538,7 @@ static void check_controls() {
 
 static void check_room_edges(int numevents_was) {
 	if ((IsInterfaceEnabled()) && (IsGamePaused() == 0) &&
-		(in_new_room == 0) && (new_room_was == 0)) {
+		(_G(in_new_room) == 0) && (_G(new_room_was) == 0)) {
 		// Only allow walking off edges if not in wait mode, and
 		// if not in Player Enters Screen (allow walking in from off-screen)
 		int edgesActivated[4] = { 0, 0, 0, 0 };
@@ -575,19 +570,19 @@ static void check_room_edges(int numevents_was) {
 			}
 		}
 	}
-	our_eip = 1008;
+	_G(our_eip) = 1008;
 
 }
 
 static void game_loop_check_controls(bool checkControls) {
 	// don't let the player do anything before the screen fades in
-	if ((in_new_room == 0) && (checkControls)) {
-		int inRoom = displayed_room;
+	if ((_G(in_new_room) == 0) && (checkControls)) {
+		int inRoom = _G(displayed_room);
 		int numevents_was = numevents;
 		check_controls();
 		check_room_edges(numevents_was);
 		// If an inventory interaction changed the room
-		if (inRoom != displayed_room)
+		if (inRoom != _G(displayed_room))
 			check_new_room();
 	}
 }
@@ -620,7 +615,7 @@ static void game_loop_do_render_and_check_mouse(IDriverDependantBitmap *extraBit
 		// TODO: move this out of render related function? find out why we remember mwasatx and mwasaty before render
 		// TODO: do not use static variables!
 		// TODO: if we support rotation then we also need to compare full transform!
-		if (displayed_room < 0)
+		if (_G(displayed_room) < 0)
 			return;
 		auto view = _GP(play).GetRoomViewportAt(_G(mousex), _G(mousey));
 		auto cam = view ? view->GetCamera() : nullptr;
@@ -648,18 +643,18 @@ static void game_loop_do_render_and_check_mouse(IDriverDependantBitmap *extraBit
 }
 
 static void game_loop_update_events() {
-	new_room_was = in_new_room;
-	if (in_new_room > 0)
+	_G(new_room_was) = _G(in_new_room);
+	if (_G(in_new_room) > 0)
 		setevent(EV_FADEIN, 0, 0, 0);
-	in_new_room = 0;
+	_G(in_new_room) = 0;
 	update_events();
-	if ((new_room_was > 0) && (in_new_room == 0)) {
+	if ((_G(new_room_was) > 0) && (_G(in_new_room) == 0)) {
 		// if in a new room, and the room wasn't just changed again in update_events,
 		// then queue the Enters Screen scripts
 		// run these next time round, when it's faded in
-		if (new_room_was == 2) // first time enters screen
+		if (_G(new_room_was) == 2) // first time enters screen
 			setevent(EV_RUNEVBLOCK, EVB_ROOM, 0, 4);
-		if (new_room_was != 3) // enters screen after fadein
+		if (_G(new_room_was) != 3) // enters screen after fadein
 			setevent(EV_RUNEVBLOCK, EVB_ROOM, 0, 7);
 	}
 }
@@ -709,7 +704,7 @@ float get_current_fps() {
 	if (isTimerFpsMaxed() && _G(fps) > 0.0f) {
 		return _G(fps);
 	}
-	return frames_per_second;
+	return _G(frames_per_second);
 }
 
 void set_loop_counter(unsigned int new_counter) {
@@ -730,7 +725,7 @@ void UpdateGameOnce(bool checkControls, IDriverDependantBitmap *extraBitmap, int
 	}
 
 	ccNotifyScriptStillAlive();
-	our_eip = 1;
+	_G(our_eip) = 1;
 
 	game_loop_check_problems_at_start();
 
@@ -738,15 +733,15 @@ void UpdateGameOnce(bool checkControls, IDriverDependantBitmap *extraBitmap, int
 	if ((_GP(play).no_hicolor_fadein) && (_GP(game).options[OPT_FADETYPE] == FADE_NORMAL))
 		_GP(play).screen_is_faded_out = 0;
 
-	our_eip = 1014;
+	_G(our_eip) = 1014;
 
 	update_gui_disabled_status();
 
-	our_eip = 1004;
+	_G(our_eip) = 1004;
 
 	game_loop_check_new_room();
 
-	our_eip = 1005;
+	_G(our_eip) = 1005;
 
 	res = game_loop_check_ground_level_interactions();
 	if (res != RETURN_CONTINUE) {
@@ -759,7 +754,7 @@ void UpdateGameOnce(bool checkControls, IDriverDependantBitmap *extraBitmap, int
 
 	game_loop_check_controls(checkControls);
 
-	our_eip = 2;
+	_G(our_eip) = 2;
 
 	game_loop_do_update();
 
@@ -771,11 +766,11 @@ void UpdateGameOnce(bool checkControls, IDriverDependantBitmap *extraBitmap, int
 
 	game_loop_do_render_and_check_mouse(extraBitmap, extraX, extraY);
 
-	our_eip = 6;
+	_G(our_eip) = 6;
 
 	game_loop_update_events();
 
-	our_eip = 7;
+	_G(our_eip) = 7;
 
 	//    if (ags_mgetbutton()>NONE) break;
 	update_polled_stuff_if_runtime();
@@ -788,7 +783,7 @@ void UpdateGameOnce(bool checkControls, IDriverDependantBitmap *extraBitmap, int
 	if (_GP(play).fast_forward)
 		return;
 
-	our_eip = 72;
+	_G(our_eip) = 72;
 
 	game_loop_update_fps();
 
@@ -857,7 +852,7 @@ static int UpdateWaitMode() {
 	}
 
 	restrict_until = ShouldStayInWaitMode();
-	our_eip = 77;
+	_G(our_eip) = 77;
 
 	if (restrict_until != 0) {
 		return RETURN_CONTINUE;
@@ -889,13 +884,13 @@ static int UpdateWaitMode() {
 
 // Run single game iteration; calls UpdateGameOnce() internally
 static int GameTick() {
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		quit("!A blocking function was called before the first room has been loaded");
 
 	UpdateGameOnce(true);
 	UpdateMouseOverLocation();
 
-	our_eip = 76;
+	_G(our_eip) = 76;
 
 	int res = UpdateWaitMode();
 	if (res == RETURN_CONTINUE) {
@@ -935,7 +930,7 @@ static void GameLoopUntilEvent(int untilwhat, const void *daaa) {
 	while (GameTick() == 0 && !_G(abort_engine)) {
 	}
 
-	our_eip = 78;
+	_G(our_eip) = 78;
 
 	restrict_until = cached_restrict_until;
 	user_disabled_data = cached_user_disabled_data;
diff --git a/engines/ags/engine/main/game_start.cpp b/engines/ags/engine/main/game_start.cpp
index 4ea936ba4d..fe67d9dad8 100644
--- a/engines/ags/engine/main/game_start.cpp
+++ b/engines/ags/engine/main/game_start.cpp
@@ -52,7 +52,6 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern int our_eip, displayed_room;
 extern CharacterInfo *playerchar;
 extern int convert_16bit_bgr;
 
@@ -83,7 +82,7 @@ void start_game() {
 	Mouse::SetPosition(Point(160, 100));
 	newmusic(0);
 
-	our_eip = -42;
+	_G(our_eip) = -42;
 
 	// skip ticks to account for initialisation or a restored _GP(game).
 	skipMissedTicks();
@@ -93,13 +92,13 @@ void start_game() {
 
 	RunTextScript(_G(gameinst), "game_start");
 
-	our_eip = -43;
+	_G(our_eip) = -43;
 
 	SetRestartPoint();
 
-	our_eip = -3;
+	_G(our_eip) = -3;
 
-	if (displayed_room < 0) {
+	if (_G(displayed_room) < 0) {
 		current_fade_out_effect();
 		load_new_room(playerchar->room, playerchar);
 		// load_new_room updates it, but it should be -1 in the first room
@@ -111,7 +110,7 @@ void start_game() {
 
 void do_start_game() {
 	// only start if replay playback hasn't loaded a game
-	if (displayed_room < 0)
+	if (_G(displayed_room) < 0)
 		start_game();
 }
 
diff --git a/engines/ags/engine/main/graphics_mode.cpp b/engines/ags/engine/main/graphics_mode.cpp
index 3293b0814b..d06bd38f60 100644
--- a/engines/ags/engine/main/graphics_mode.cpp
+++ b/engines/ags/engine/main/graphics_mode.cpp
@@ -50,8 +50,7 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern int proper_exit;
-extern AGSPlatformDriver *platform;
+
 extern IGraphicsDriver *gfxDriver;
 
 GameFrameSetup::GameFrameSetup()
@@ -89,7 +88,7 @@ Size get_desktop_size() {
 Size get_max_display_size(bool windowed) {
 	Size device_size = get_desktop_size();
 	if (windowed)
-		platform->ValidateWindowSize(device_size.Width, device_size.Height, false);
+		_G(platform)->ValidateWindowSize(device_size.Width, device_size.Height, false);
 	return device_size;
 }
 
@@ -408,8 +407,8 @@ bool simple_create_gfx_driver_and_init_mode(const String &gfx_driver_id,
 
 
 void display_gfx_mode_error(const Size &game_size, const ScreenSetup &setup, const int color_depth) {
-	proper_exit = 1;
-	platform->FinishedUsingGraphicsMode();
+	_G(proper_exit) = true;
+	_G(platform)->FinishedUsingGraphicsMode();
 
 	String main_error;
 	ScreenSizeSetup scsz = setup.DisplayMode.ScreenSize;
@@ -422,11 +421,11 @@ void display_gfx_mode_error(const Size &game_size, const ScreenSetup &setup, con
 		main_error.Format("There was a problem finding and/or creating valid graphics mode for game size %d x %d (%d-bit) and requested filter '%s'.",
 			game_size.Width, game_size.Height, color_depth, setup.Filter.UserRequest.IsEmpty() ? "Undefined" : setup.Filter.UserRequest.GetCStr());
 
-	platform->DisplayAlert("%s\n"
+	_G(platform)->DisplayAlert("%s\n"
 		"(Problem: '%s')\n"
 		"Try to correct the problem, or seek help from the AGS homepage."
 		"%s",
-		main_error.GetCStr(), get_allegro_error(), platform->GetGraphicsTroubleshootingText());
+		main_error.GetCStr(), get_allegro_error(), _G(platform)->GetGraphicsTroubleshootingText());
 }
 
 bool graphics_mode_init_any(const Size game_size, const ScreenSetup &setup, const ColorDepthOption &color_depth) {
diff --git a/engines/ags/engine/main/quit.cpp b/engines/ags/engine/main/quit.cpp
index 2caa7a833c..8c5cd4136d 100644
--- a/engines/ags/engine/main/quit.cpp
+++ b/engines/ags/engine/main/quit.cpp
@@ -54,9 +54,7 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-extern int our_eip;
 extern char pexbuf[STD_BUFFER_SIZE];
-extern int proper_exit;
 extern char check_dynamic_sprites_at_exit;
 extern int need_to_stop_cd;
 extern int use_cdplayer;
@@ -98,23 +96,23 @@ void quit_check_dynamic_sprites(QuitReason qreason) {
 
 void quit_shutdown_platform(QuitReason qreason) {
 	// Be sure to unlock mouse on exit, or users will hate us
-	platform->UnlockMouse();
-	platform->AboutToQuitGame();
+	_G(platform)->UnlockMouse();
+	_G(platform)->AboutToQuitGame();
 
-	our_eip = 9016;
+	_G(our_eip) = 9016;
 
 	pl_stop_plugins();
 
 	quit_check_dynamic_sprites(qreason);
 
-	platform->FinishedUsingGraphicsMode();
+	_G(platform)->FinishedUsingGraphicsMode();
 
 	if (use_cdplayer)
-		platform->ShutdownCDPlayer();
+		_G(platform)->ShutdownCDPlayer();
 }
 
 void quit_shutdown_audio() {
-	our_eip = 9917;
+	_G(our_eip) = 9917;
 	_GP(game).options[OPT_CROSSFADEMUSIC] = 0;
 	shutdown_sound();
 }
@@ -168,7 +166,7 @@ void quit_message_on_exit(const char *qmsg, String &alertis, QuitReason qreason)
 		// Display the message (at this point the window still exists)
 		sprintf(pexbuf, "%s\n", qmsg);
 		alertis.Append(pexbuf);
-		platform->DisplayAlert("%s", alertis.GetCStr());
+		_G(platform)->DisplayAlert("%s", alertis.GetCStr());
 	}
 }
 
@@ -235,32 +233,32 @@ void quit_free() {
 
 	quit_tell_editor_debugger(_G(quit_message), qreason);
 
-	our_eip = 9900;
+	_G(our_eip) = 9900;
 
 	quit_stop_cd();
 
-	our_eip = 9020;
+	_G(our_eip) = 9020;
 
 	quit_shutdown_scripts();
 
 	quit_shutdown_platform(qreason);
 
-	our_eip = 9019;
+	_G(our_eip) = 9019;
 
 	quit_shutdown_audio();
 
-	our_eip = 9901;
+	_G(our_eip) = 9901;
 
 	shutdown_font_renderer();
-	our_eip = 9902;
+	_G(our_eip) = 9902;
 
 	_GP(spriteset).Reset();
 
-	our_eip = 9907;
+	_G(our_eip) = 9907;
 
 	close_translation();
 
-	our_eip = 9908;
+	_G(our_eip) = 9908;
 
 	shutdown_pathfinder();
 
@@ -275,19 +273,19 @@ void quit_free() {
 	// if their destruction is called later, program will crash!
 	allegro_exit();
 
-	platform->PostAllegroExit();
+	_G(platform)->PostAllegroExit();
 
-	our_eip = 9903;
+	_G(our_eip) = 9903;
 
 	quit_delete_temp_files();
 
-	proper_exit = 1;
+	_G(proper_exit) = 1;
 
 	Debug::Printf(kDbgMsg_Alert, "***** ENGINE HAS SHUTDOWN");
 
 	shutdown_debug();
 
-	our_eip = 9904;
+	_G(our_eip) = 9904;
 }
 
 extern "C" {
diff --git a/engines/ags/engine/main/update.cpp b/engines/ags/engine/main/update.cpp
index d36f65c7cf..bc9a1df257 100644
--- a/engines/ags/engine/main/update.cpp
+++ b/engines/ags/engine/main/update.cpp
@@ -54,13 +54,6 @@ namespace AGS3 {
 using namespace AGS::Shared;
 using namespace AGS::Engine;
 
-
-extern RoomStatus *croom;
-
-
-extern RoomObject *objs;
-
-extern int our_eip;
 extern CharacterInfo *playerchar;
 extern CharacterExtras *charextra;
 extern CharacterInfo *facetalkchar;
@@ -198,9 +191,9 @@ void update_script_timers() {
 
 void update_cycling_views() {
 	// update graphics for object if cycling view
-	for (int aa = 0; aa < croom->numobj; aa++) {
+	for (int aa = 0; aa < _G(croom)->numobj; aa++) {
 
-		RoomObject *obj = &objs[aa];
+		RoomObject *obj = &_G(objs)[aa];
 
 		obj->UpdateCyclingView();
 	}
@@ -441,17 +434,17 @@ void update_sierra_speech() {
 // the like.
 void update_stuff() {
 
-	our_eip = 20;
+	_G(our_eip) = 20;
 
 	update_script_timers();
 
 	update_cycling_views();
 
-	our_eip = 21;
+	_G(our_eip) = 21;
 
 	update_shadow_areas();
 
-	our_eip = 22;
+	_G(our_eip) = 22;
 
 	int numSheep = 0;
 	int followingAsSheep[MAX_SHEEP];
@@ -460,17 +453,17 @@ void update_stuff() {
 
 	update_following_exactly_characters(numSheep, followingAsSheep);
 
-	our_eip = 23;
+	_G(our_eip) = 23;
 
 	update_overlay_timers();
 
 	update_speech_and_messages();
 
-	our_eip = 24;
+	_G(our_eip) = 24;
 
 	update_sierra_speech();
 
-	our_eip = 25;
+	_G(our_eip) = 25;
 }
 
 } // namespace AGS3
diff --git a/engines/ags/engine/media/audio/audio.cpp b/engines/ags/engine/media/audio/audio.cpp
index b847f01d5d..0487e6b750 100644
--- a/engines/ags/engine/media/audio/audio.cpp
+++ b/engines/ags/engine/media/audio/audio.cpp
@@ -102,8 +102,6 @@ void set_clip_to_channel(int chanid, SOUNDCLIP *clip) {
 
 extern CharacterInfo *playerchar;
 
-extern volatile int switching_away_from_game;
-
 void calculate_reserved_channel_count() {
 	int reservedChannels = 0;
 	for (size_t i = 0; i < _GP(game).audioClipTypes.size(); i++) {
diff --git a/engines/ags/engine/platform/base/agsplatformdriver.cpp b/engines/ags/engine/platform/base/agsplatformdriver.cpp
index a301f1aae3..9f0eaa759b 100644
--- a/engines/ags/engine/platform/base/agsplatformdriver.cpp
+++ b/engines/ags/engine/platform/base/agsplatformdriver.cpp
@@ -55,7 +55,6 @@ using namespace AGS::Engine;
 const auto MaximumDelayBetweenPolling = std::chrono::milliseconds(16);
 
 AGSPlatformDriver *AGSPlatformDriver::instance = nullptr;
-AGSPlatformDriver *platform = nullptr;
 
 // ******** DEFAULT IMPLEMENTATIONS *******
 
diff --git a/engines/ags/engine/platform/base/agsplatformdriver.h b/engines/ags/engine/platform/base/agsplatformdriver.h
index 4f056c3341..df140d4844 100644
--- a/engines/ags/engine/platform/base/agsplatformdriver.h
+++ b/engines/ags/engine/platform/base/agsplatformdriver.h
@@ -204,7 +204,7 @@ int cd_player_control(int cmdd, int datt);
 
 // [IKM] What is a need to have this global var if you can get AGSPlatformDriver
 // instance by calling AGSPlatformDriver::GetDriver()?
-extern AGSPlatformDriver *platform;
+
 
 } // namespace AGS3
 
diff --git a/engines/ags/engine/platform/windows/acplwin.cpp b/engines/ags/engine/platform/windows/acplwin.cpp
index b01a694a10..54ca3377ea 100644
--- a/engines/ags/engine/platform/windows/acplwin.cpp
+++ b/engines/ags/engine/platform/windows/acplwin.cpp
@@ -54,7 +54,7 @@ using namespace AGS::Shared;
 using namespace AGS::Engine;
 
 extern GameSetup usetup;
-extern int our_eip;
+extern int _G(our_eip);
 extern IGraphicsDriver *gfxDriver;
 extern color palette[256];
 
@@ -788,7 +788,7 @@ int AGSWin32::GetLastSystemError() {
 unsigned long AGSWin32::GetDiskFreeSpaceMB() {
 	DWORD returnMb = 0;
 	BOOL fResult;
-	our_eip = -1891;
+	_G(our_eip) = -1891;
 
 	// On Win9x, the last 3 params cannot be null, so need to supply values for all
 	__int64 i64FreeBytesToCaller, i64Unused1, i64Unused2;
@@ -801,7 +801,7 @@ unsigned long AGSWin32::GetDiskFreeSpaceMB() {
 	                             (PULARGE_INTEGER)&i64Unused1,
 	                             (PULARGE_INTEGER)&i64Unused2);
 
-	our_eip = -1893;
+	_G(our_eip) = -1893;
 
 	// convert down to MB so we can fit it in a 32-bit long
 	i64FreeBytesToCaller /= 1000000;
diff --git a/engines/ags/engine/platform/windows/win_ex_handling.cpp b/engines/ags/engine/platform/windows/win_ex_handling.cpp
index de3fcd9150..e08c6d7118 100644
--- a/engines/ags/engine/platform/windows/win_ex_handling.cpp
+++ b/engines/ags/engine/platform/windows/win_ex_handling.cpp
@@ -41,7 +41,7 @@ namespace AGS3 {
 
 using namespace AGS::Shared;
 
-extern int our_eip;
+extern int _G(our_eip);
 extern int eip_guinum;
 extern int eip_guiobj;
 extern int proper_exit;
@@ -61,7 +61,7 @@ static void DisplayException() {
 	sprintf(printfworkingspace, "An exception 0x%X occurred in ACWIN.EXE at EIP = 0x%08X; program pointer is %+d, ACI version %s, gtags (%d,%d)\n\n"
 	        "AGS cannot continue, this exception was fatal. Please note down the numbers above, remember what you were doing at the time and post the details on the AGS Technical Forum.\n\n%s\n\n"
 	        "Most versions of Windows allow you to press Ctrl+C now to copy this entire message to the clipboard for easy reporting.\n\n%s (code %d)",
-	        excinfo.ExceptionCode, (intptr_t)excinfo.ExceptionAddress, our_eip, EngineVersion.LongString.GetCStr(), eip_guinum, eip_guiobj, script_callstack.GetCStr(),
+	        excinfo.ExceptionCode, (intptr_t)excinfo.ExceptionAddress, _G(our_eip), EngineVersion.LongString.GetCStr(), eip_guinum, eip_guiobj, script_callstack.GetCStr(),
 	        (miniDumpResultCode == 0) ? "An error file CrashInfo.dmp has been created. You may be asked to upload this file when reporting this problem on the AGS Forums." :
 	        "Unable to create an error dump file.", miniDumpResultCode);
 	MessageBoxA(win_get_window(), printfworkingspace, "Illegal exception", MB_ICONSTOP | MB_OK);
@@ -87,7 +87,7 @@ int malloc_fail_handler(size_t amountwanted) {
 	CreateMiniDump(NULL);
 #endif
 	free(printfworkingspace);
-	sprintf(tempmsg, "Out of memory: failed to allocate %ld bytes (at PP=%d)", amountwanted, our_eip);
+	sprintf(tempmsg, "Out of memory: failed to allocate %ld bytes (at PP=%d)", amountwanted, _G(our_eip));
 	quit(tempmsg);
 	return 0;
 }
diff --git a/engines/ags/engine/script/script.cpp b/engines/ags/engine/script/script.cpp
index 296ff16715..65dd3bc5c0 100644
--- a/engines/ags/engine/script/script.cpp
+++ b/engines/ags/engine/script/script.cpp
@@ -54,10 +54,8 @@
 
 namespace AGS3 {
 
-extern int gameHasBeenRestored, displayed_room;
+extern int gameHasBeenRestored;
 extern unsigned int load_new_game;
-extern RoomObject *objs;
-extern int our_eip;
 extern CharacterInfo *playerchar;
 
 int run_dialog_request(int parmtr) {
@@ -407,7 +405,7 @@ int RunTextScript(ccInstance *sci, const char *tsname) {
 	int toret = RunScriptFunctionIfExists(sci, tsname, 0, nullptr);
 	if ((toret == -18) && (sci == _G(roominst))) {
 		// functions in room script must exist
-		quitprintf("prepare_script: error %d (%s) trying to run '%s'   (Room %d)", toret, _G(ccErrorString).GetCStr(), tsname, displayed_room);
+		quitprintf("prepare_script: error %d (%s) trying to run '%s'   (Room %d)", toret, _G(ccErrorString).GetCStr(), tsname, _G(displayed_room));
 	}
 	return toret;
 }
@@ -452,7 +450,7 @@ String GetScriptName(ccInstance *sci) {
 	else if (sci->instanceof == _GP(gamescript))
 		return "Global script";
 	else if (sci->instanceof == _GP(thisroom).CompiledScript)
-		return String::FromFormat("Room %d script", displayed_room);
+		return String::FromFormat("Room %d script", _G(displayed_room));
 	return "Unknown script";
 }
 
@@ -486,7 +484,7 @@ void post_script_cleanup() {
 	}
 	//  if (abort_executor) user_disabled_data2=aborted_ip;
 
-	int old_room_number = displayed_room;
+	int old_room_number = _G(displayed_room);
 
 	// run the queued post-script actions
 	for (int ii = 0; ii < copyof.numPostScriptActions; ii++) {
@@ -534,7 +532,7 @@ void post_script_cleanup() {
 			quitprintf("undefined post script action found: %d", copyof.postScriptActions[ii]);
 		}
 		// if the room changed in a conversation, for example, abort
-		if (old_room_number != displayed_room) {
+		if (old_room_number != _G(displayed_room)) {
 			return;
 		}
 	}
@@ -542,7 +540,7 @@ void post_script_cleanup() {
 
 	int jj;
 	for (jj = 0; jj < copyof.numanother; jj++) {
-		old_room_number = displayed_room;
+		old_room_number = _G(displayed_room);
 		QueuedScript &script = copyof.ScFnQueue[jj];
 		RunScriptFunction(script.Instance, script.FnName, script.ParamCount, script.Param1, script.Param2);
 		if (script.Instance == kScInstRoom && script.ParamCount == 1) {
@@ -551,7 +549,7 @@ void post_script_cleanup() {
 		}
 
 		// if they've changed rooms, cancel any further pending scripts
-		if ((displayed_room != old_room_number) || (load_new_game))
+		if ((_G(displayed_room) != old_room_number) || (load_new_game))
 			break;
 	}
 	copyof.numanother = 0;
@@ -609,11 +607,11 @@ InteractionVariable *FindGraphicalVariable(const char *varName) {
 struct TempEip {
 	int oldval;
 	TempEip(int newval) {
-		oldval = our_eip;
-		our_eip = newval;
+		oldval = _G(our_eip);
+		_G(our_eip) = newval;
 	}
 	~TempEip() {
-		our_eip = oldval;
+		_G(our_eip) = oldval;
 	}
 };
 
@@ -701,7 +699,7 @@ int run_interaction_commandlist(InteractionCommandList *nicl, int *timesrun, int
 			MoveObject(IPARAM1, IPARAM2, IPARAM3, IPARAM4);
 			// if they want to wait until finished, do so
 			if (IPARAM5)
-				GameLoopUntilNotMoving(&objs[IPARAM1].moving);
+				GameLoopUntilNotMoving(&_G(objs)[IPARAM1].moving);
 			break;
 		case 15: // Object Off
 			ObjectOff(IPARAM1);
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 5dc330784e..38d9cade56 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -27,6 +27,7 @@
 #include "ags/shared/util/version.h"
 #include "ags/shared/gui/guimain.h"
 #include "ags/shared/script/cc_script.h"
+#include "ags/engine/ac/runtime_defines.h"
 #include "ags/engine/main/engine.h"
 #include "ags/engine/media/audio/audiodefines.h"
 #include "ags/lib/std/array.h"
@@ -78,6 +79,7 @@ class TTFFontRenderer;
 class WFNFontRenderer;
 
 struct ActiveDisplaySetting;
+struct AGSPlatformDriver;
 struct AmbientSound;
 struct AnimatingGUIButton;
 struct CCAudioChannel;
@@ -107,6 +109,7 @@ struct ObjectCache;
 struct ResourcePaths;
 struct RGB_MAP;
 struct RoomCameraDrawData;
+struct RoomObject;
 struct RoomStatus;
 struct RuntimeScriptValue;
 struct ScreenOverlay;
@@ -171,6 +174,15 @@ public:
 
 	/**@}*/
 
+	/**
+	 * \defgroup audio globals
+	 * @{
+	 */
+
+	AGSPlatformDriver *_platform = nullptr;
+
+	/**@}*/
+
 	/**
 	 * \defgroup audio globals
 	 * @{
@@ -407,11 +419,23 @@ public:
 	AGS::Shared::String _saveGameDirectory;
 	AGS::Shared::String _saveGameParent;
 	AGS::Shared::String _saveGameSuffix;
-
-	// Major overall flags
 	bool _want_exit = false;
 	bool _abort_engine = false;
 
+	RoomObject *_objs;
+	RoomStatus *_croom = nullptr;
+
+	volatile int _switching_away_from_game = 0;
+	volatile bool _switched_away = false;
+	int _frames_per_second = 40;
+	int _displayed_room = -10, _starting_room = -1;
+	int _in_new_room = 0, _new_room_was = 0; // 1 in new room, 2 first time in new room, 3 loading saved game
+	int _new_room_pos = 0;
+	int _new_room_x = SCR_NO_VALUE, _new_room_y = SCR_NO_VALUE;
+	int _new_room_loop = SCR_NO_VALUE;
+	bool _proper_exit = false;
+	int _our_eip = 0;
+
 	 /**@}*/
 
 	/**
diff --git a/engines/ags/plugins/agsplugin.cpp b/engines/ags/plugins/agsplugin.cpp
index c8fafb2ebd..27d92f7ea1 100644
--- a/engines/ags/plugins/agsplugin.cpp
+++ b/engines/ags/plugins/agsplugin.cpp
@@ -85,9 +85,6 @@ using namespace AGS::Shared::Memory;
 using namespace AGS::Engine;
 
 extern IGraphicsDriver *gfxDriver;
-extern int displayed_room;
-extern RoomStatus *croom;
-
 extern int game_paused;
 extern color palette[256];
 extern PluginObjectReader pluginReaders[MAX_PLUGIN_OBJECT_READERS];
@@ -279,7 +276,7 @@ void IAGSEngine::GetMousePosition(int32 *x, int32 *y) {
 	if (y) y[0] = _G(mousey);
 }
 int IAGSEngine::GetCurrentRoom() {
-	return displayed_room;
+	return _G(displayed_room);
 }
 int IAGSEngine::GetNumBackgrounds() {
 	return _GP(thisroom).BgFrameCount;
@@ -455,13 +452,13 @@ void IAGSEngine::ViewportToRoom(int32 *x, int32 *y) {
 		*y = vpt.first.Y;
 }
 int IAGSEngine::GetNumObjects() {
-	return croom->numobj;
+	return _G(croom)->numobj;
 }
 AGSObject *IAGSEngine::GetObject(int32 num) {
-	if (num >= croom->numobj)
+	if (num >= _G(croom)->numobj)
 		quit("!IAGSEngine::GetObject: invalid object");
 
-	return (AGSObject *)&croom->obj[num];
+	return (AGSObject *)&_G(croom)->obj[num];
 }
 BITMAP *IAGSEngine::CreateBlankBitmap(int32 width, int32 height, int32 coldep) {
 	// [IKM] We should not create Bitmap object here, because
@@ -515,7 +512,7 @@ int IAGSEngine::GetRawPixelColor(int32 color) {
 int IAGSEngine::GetWalkbehindBaseline(int32 wa) {
 	if ((wa < 1) || (wa >= MAX_WALK_BEHINDS))
 		quit("!IAGSEngine::GetWalkBehindBase: invalid walk-behind area specified");
-	return croom->walkbehind_base[wa];
+	return _G(croom)->walkbehind_base[wa];
 }
 void *IAGSEngine::GetScriptFunctionAddress(const char *funcName) {
 	return ccGetSymbolAddressForPlugin((const char *)funcName);
@@ -550,7 +547,7 @@ void IAGSEngine::GetTextExtent(int32 font, const char *text, int32 *width, int32
 }
 void IAGSEngine::PrintDebugConsole(const char *text) {
 	debug_script_log("[PLUGIN] %s", text);
-	platform->WriteStdOut("[PLUGIN] %s", text);
+	_G(platform)->WriteStdOut("[PLUGIN] %s", text);
 }
 int IAGSEngine::IsChannelPlaying(int32 channel) {
 	return AGS3::IsChannelPlaying(channel);
diff --git a/engines/ags/shared/font/wfnfontrenderer.cpp b/engines/ags/shared/font/wfnfontrenderer.cpp
index 301d4ee281..762ba4b2fa 100644
--- a/engines/ags/shared/font/wfnfontrenderer.cpp
+++ b/engines/ags/shared/font/wfnfontrenderer.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include "ags/shared/ac/common.h" // our_eip
+#include "ags/shared/ac/common.h" // _G(our_eip)
 #include "ags/shared/core/assetmanager.h"
 #include "ags/shared/debugging/out.h"
 #include "ags/shared/font/wfnfont.h"




More information about the Scummvm-git-logs mailing list