[Scummvm-git-logs] scummvm master -> e7d51b856de33783fae0f1ef18c21bab34eee2fb

criezy criezy at scummvm.org
Sat Mar 6 21:23:38 UTC 2021


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

Summary:
65e70b8202 AGS: Remove useless C-style casts
0f88911e04 AGS: Do proper BITMAP class forward declaration for plugins
8491d62fa6 AGS: Fix access to bitmaps in plugins
551d03a7b4 AGS: Plug memory leak in SpriteFont plugin
6c117d04dd AGS: Implement AGSSpriteFont plugin variant from Clifftop Games
e7d51b856d AGS: Use AGSSpritePlugin variant for Kathy Rain and WoaM


Commit: 65e70b8202093811001c1ea2a0301996f53af271
    https://github.com/scummvm/scummvm/commit/65e70b8202093811001c1ea2a0301996f53af271
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2021-03-06T21:21:22Z

Commit Message:
AGS: Remove useless C-style casts

Changed paths:
    engines/ags/plugins/agsplugin.cpp
    engines/ags/shared/font/fonts.cpp


diff --git a/engines/ags/plugins/agsplugin.cpp b/engines/ags/plugins/agsplugin.cpp
index 004c8b8c49..47bb836b77 100644
--- a/engines/ags/plugins/agsplugin.cpp
+++ b/engines/ags/plugins/agsplugin.cpp
@@ -472,7 +472,7 @@ void IAGSEngine::FreeBitmap(BITMAP *tofree) {
 		destroy_bitmap(tofree);
 }
 BITMAP *IAGSEngine::GetSpriteGraphic(int32 num) {
-	return (BITMAP *)_GP(spriteset)[num]->GetAllegroBitmap();
+	return _GP(spriteset)[num]->GetAllegroBitmap();
 }
 BITMAP *IAGSEngine::GetRoomMask(int32 index) {
 	if (index == MASK_WALKABLE)
diff --git a/engines/ags/shared/font/fonts.cpp b/engines/ags/shared/font/fonts.cpp
index bb2e18b5cc..537eab4b61 100644
--- a/engines/ags/shared/font/fonts.cpp
+++ b/engines/ags/shared/font/fonts.cpp
@@ -291,7 +291,7 @@ void wouttextxy(Shared::Bitmap *ds, int xxx, int yyy, size_t fontNumber, color_t
 		return;                   // each char is clipped but this speeds it up
 
 	if (_GP(fonts)[fontNumber].Renderer != nullptr) {
-		_GP(fonts)[fontNumber].Renderer->RenderText(texx, fontNumber, (BITMAP *)ds->GetAllegroBitmap(), xxx, yyy, text_color);
+		_GP(fonts)[fontNumber].Renderer->RenderText(texx, fontNumber, ds->GetAllegroBitmap(), xxx, yyy, text_color);
 	}
 }
 


Commit: 0f88911e04034554b3e942c2db8b859ab1644568
    https://github.com/scummvm/scummvm/commit/0f88911e04034554b3e942c2db8b859ab1644568
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2021-03-06T21:21:22Z

Commit Message:
AGS: Do proper BITMAP class forward declaration for plugins

Changed paths:
    engines/ags/plugins/agsplugin.h


diff --git a/engines/ags/plugins/agsplugin.h b/engines/ags/plugins/agsplugin.h
index e834d166da..b1efb262e8 100644
--- a/engines/ags/plugins/agsplugin.h
+++ b/engines/ags/plugins/agsplugin.h
@@ -55,10 +55,8 @@ typedef void *LPDIRECTSOUND;
 typedef void *LPDIRECTINPUTDEVICE;
 #endif
 
-// If the user isn't using Allegro or WinGDI, define the BITMAP into something
-#if !defined(ALLEGRO_H) && !defined(_WINGDI_) && !defined(BITMAP_DEFINED)
-typedef char BITMAP;
-#endif
+// Forward declaration of BITMAP class
+class BITMAP;
 
 // If not using windows.h, define HWND
 #if !defined(_WINDOWS_)


Commit: 8491d62fa6ed21ab2cdf7d34caab0a069887315a
    https://github.com/scummvm/scummvm/commit/8491d62fa6ed21ab2cdf7d34caab0a069887315a
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2021-03-06T21:21:22Z

Commit Message:
AGS: Fix access to bitmaps in plugins

In ScummVM bitmap data are stored linearly but plugins
were accessing those as array of arrays leading to
out of bound memory access.

Changed paths:
    engines/ags/plugins/ags_blend/ags_blend.cpp
    engines/ags/plugins/ags_creditz/ags_creditz2.cpp
    engines/ags/plugins/ags_creditz/drawing.h
    engines/ags/plugins/ags_flashlight/ags_flashlight.cpp
    engines/ags/plugins/ags_flashlight/ags_flashlight.h
    engines/ags/plugins/ags_pal_render/ags_pal_render.cpp
    engines/ags/plugins/ags_pal_render/pal_render.h
    engines/ags/plugins/ags_pal_render/raycast.cpp
    engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
    engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
    engines/ags/plugins/agsplugin.cpp
    engines/ags/plugins/agsplugin.h


diff --git a/engines/ags/plugins/ags_blend/ags_blend.cpp b/engines/ags/plugins/ags_blend/ags_blend.cpp
index 5950c644e5..9942bff89f 100644
--- a/engines/ags/plugins/ags_blend/ags_blend.cpp
+++ b/engines/ags/plugins/ags_blend/ags_blend.cpp
@@ -154,10 +154,11 @@ void AGSBlend::GetAlpha(ScriptMethodParams &params) {
 	PARAMS3(int, sprite, int, x, int, y);
 	BITMAP *engineSprite = _engine->GetSpriteGraphic(sprite);
 
-	unsigned char **charbuffer = _engine->GetRawBitmapSurface(engineSprite);
-	unsigned int **longbuffer = (unsigned int **)charbuffer;
+	uint8 *charbuffer = _engine->GetRawBitmapSurface(engineSprite);
+	uint32 *longbuffer = (uint32 *)charbuffer;
+	int pitch = _engine->GetBitmapPitch(engineSprite) / 4;
 
-	int alpha = geta32(longbuffer[y][x]);
+	int alpha = geta32(longbuffer[y * pitch + x]);
 
 	_engine->ReleaseBitmapSurface(engineSprite);
 
@@ -168,14 +169,15 @@ void AGSBlend::PutAlpha(ScriptMethodParams &params) {
 	PARAMS4(int, sprite, int, x, int, y, int, alpha);
 	BITMAP *engineSprite = _engine->GetSpriteGraphic(sprite);
 
-	unsigned char **charbuffer = _engine->GetRawBitmapSurface(engineSprite);
-	unsigned int **longbuffer = (unsigned int **)charbuffer;
+	uint8 *charbuffer = _engine->GetRawBitmapSurface(engineSprite);
+	uint32 *longbuffer = (uint32 *)charbuffer;
+	int pitch = _engine->GetBitmapPitch(engineSprite) / 4;
 
-
-	int r = getr32(longbuffer[y][x]);
-	int g = getg32(longbuffer[y][x]);
-	int b = getb32(longbuffer[y][x]);
-	longbuffer[y][x] = makeacol32(r, g, b, alpha);
+	int pixel = y * pitch + x;
+	int r = getr32(longbuffer[pixel]);
+	int g = getg32(longbuffer[pixel]);
+	int b = getb32(longbuffer[pixel]);
+	longbuffer[pixel] = makeacol32(r, g, b, alpha);
 
 	_engine->ReleaseBitmapSurface(engineSprite);
 
@@ -193,22 +195,24 @@ void AGSBlend::HighPass(ScriptMethodParams &params) {
 
 	_engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, nullptr);
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer;
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint32 *srclongbuffer = (uint32 *)srccharbuffer;
+	int pitch = _engine->GetBitmapPitch(src) / 4;
 
-	for (int y = 0; y < srcHeight; y++) {
+	for (int y = 0, yi = 0; y < srcHeight; y++, yi += pitch) {
 
 		for (int x = 0; x < srcWidth; x++) {
 
-			int srcr = getb32(srclongbuffer[y][x]);
-			int srcg = getg32(srclongbuffer[y][x]);
-			int srcb = getr32(srclongbuffer[y][x]);
+			int srcr = getb32(srclongbuffer[yi + x]);
+			int srcg = getg32(srclongbuffer[yi + x]);
+			int srcb = getr32(srclongbuffer[yi + x]);
 			int tempmaxim = max(srcr, srcg);
 			int maxim = max(tempmaxim, srcb);
 			int tempmin = min(srcr, srcg);
 			int minim = min(srcb, tempmin);
 			int light = (maxim + minim) / 2 ;
-			if (light < threshold) srclongbuffer[y][x] = makeacol32(0, 0, 0, 0);
+			if (light < threshold)
+				srclongbuffer[yi + x] = makeacol32(0, 0, 0, 0);
 
 		}
 
@@ -225,8 +229,9 @@ void AGSBlend::Blur(ScriptMethodParams &params) {
 	int32 srcWidth, srcHeight;
 	_engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, nullptr);
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer;
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint32 *srclongbuffer = (uint32 *)srccharbuffer;
+	int pitch = _engine->GetBitmapPitch(src) / 4;
 	int negrad = -1 * radius;
 
 	//use a 1Dimensional array since the array is on the free store, not the stack
@@ -236,14 +241,14 @@ void AGSBlend::Blur(ScriptMethodParams &params) {
 
 	int arraywidth = srcWidth + (radius * 2); //define the array width since its used many times in the algorithm
 
-	for (int y = 0; y < srcHeight; y++) { //copy the sprite to the Pixels class array
+	for (int y = 0, yi = 0; y < srcHeight; y++, yi += pitch) { //copy the sprite to the Pixels class array
 		for (int x = 0; x < srcWidth; x++) {
 			int locale = xytolocale(x + radius, y + radius, arraywidth);
 
-			Pixels[locale].Red = getr32(srclongbuffer[y][x]);
-			Pixels[locale].Green = getg32(srclongbuffer[y][x]);
-			Pixels[locale].Blue = getb32(srclongbuffer[y][x]);
-			Pixels[locale].Alpha = geta32(srclongbuffer[y][x]);
+			Pixels[locale].Red = getr32(srclongbuffer[yi + x]);
+			Pixels[locale].Green = getg32(srclongbuffer[yi + x]);
+			Pixels[locale].Blue = getb32(srclongbuffer[yi + x]);
+			Pixels[locale].Alpha = geta32(srclongbuffer[yi + x]);
 		}
 	}
 
@@ -342,11 +347,11 @@ void AGSBlend::Blur(ScriptMethodParams &params) {
 		}
 	}
 
-	for (int y = 0; y < srcHeight; y++) {
+	for (int y = 0, yi = 0; y < srcHeight; y++, yi += pitch) {
 
 		for (int x = 0; x < srcWidth; x++) {
 			int locale = xytolocale(x + radius, y + radius, arraywidth);
-			srclongbuffer[y][x] = Dest[locale].GetColorAsInt(); //write the destination array to the main buffer
+			srclongbuffer[yi + x] = Dest[locale].GetColorAsInt(); //write the destination array to the main buffer
 		}
 	}
 
@@ -377,16 +382,17 @@ void AGSBlend::DrawSprite(ScriptMethodParams &params) {
 		return;
 	}
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer;
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint32 *srclongbuffer = (uint32 *)srccharbuffer;
+	int srcPitch = _engine->GetBitmapPitch(src) / 4;
 
-	unsigned char **destcharbuffer = _engine->GetRawBitmapSurface(dest);
-	unsigned int **destlongbuffer = (unsigned int **)destcharbuffer;
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
+	uint32 *destlongbuffer = (uint32 *)destcharbuffer;
+	int destPitch = _engine->GetBitmapPitch(dest) / 4;
 
 	if (srcWidth + x > destWidth) srcWidth = destWidth - x - 1;
 	if (srcHeight + y > destHeight) srcHeight = destHeight - y - 1;
 
-	int destx, desty;
 	int srcr, srcg, srcb, srca, destr, destg, destb, desta;
 	int finalr = 0, finalg = 0, finalb = 0, finala = 0;
 	unsigned int col;
@@ -398,23 +404,24 @@ void AGSBlend::DrawSprite(ScriptMethodParams &params) {
 
 	int ycount = 0;
 	int xcount = 0;
-	for (ycount = starty; ycount < srcHeight; ycount ++) {
+	int srcy = starty * srcPitch;
+	int desty = (starty + y) * destPitch;
+	for (ycount = starty; ycount < srcHeight; ycount ++, srcy += srcPitch, desty += destPitch) {
 		for (xcount = startx; xcount < srcWidth; xcount ++) {
-			destx = xcount + x;
-			desty = ycount + y;
+			int destx = xcount + x;
 
-			srca = (geta32(srclongbuffer[ycount][xcount]));
+			srca = (geta32(srclongbuffer[srcy + xcount]));
 
 			if (srca != 0) {
 				srca = srca * trans / 100;
-				srcr =  getr32(srclongbuffer[ycount][xcount]);
-				srcg =  getg32(srclongbuffer[ycount][xcount]);
-				srcb =  getb32(srclongbuffer[ycount][xcount]);
+				srcr =  getr32(srclongbuffer[srcy + xcount]);
+				srcg =  getg32(srclongbuffer[srcy + xcount]);
+				srcb =  getb32(srclongbuffer[srcy + xcount]);
 
-				destr =  getr32(destlongbuffer[desty][destx]);
-				destg =  getg32(destlongbuffer[desty][destx]);
-				destb =  getb32(destlongbuffer[desty][destx]);
-				desta =  geta32(destlongbuffer[desty][destx]);
+				destr =  getr32(destlongbuffer[desty + destx]);
+				destg =  getg32(destlongbuffer[desty + destx]);
+				destb =  getb32(destlongbuffer[desty + destx]);
+				desta =  geta32(destlongbuffer[desty + destx]);
 
 				switch (DrawMode) {
 				case 0:
@@ -570,7 +577,7 @@ void AGSBlend::DrawSprite(ScriptMethodParams &params) {
 				finalg = srca * finalg / finala + desta * destg * (255 - srca) / finala / 255;
 				finalb = srca * finalb / finala + desta * destb * (255 - srca) / finala / 255;
 				col = makeacol32(finalr, finalg, finalb, finala);
-				destlongbuffer[desty][destx] = col;
+				destlongbuffer[desty + destx] = col;
 
 			}
 
@@ -602,16 +609,17 @@ void AGSBlend::DrawAdd(ScriptMethodParams &params) {
 		return;
 	}
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer;
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint32 *srclongbuffer = (uint32 *)srccharbuffer;
+	int srcPitch = _engine->GetBitmapPitch(src) / 4;
 
-	unsigned char **destcharbuffer = _engine->GetRawBitmapSurface(dest);
-	unsigned int **destlongbuffer = (unsigned int **)destcharbuffer;
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
+	uint32 *destlongbuffer = (uint32 *)destcharbuffer;
+	int destPitch = _engine->GetBitmapPitch(dest) / 4;
 
 	if (srcWidth + x > destWidth) srcWidth = destWidth - x - 1;
 	if (srcHeight + y > destHeight) srcHeight = destHeight - y - 1;
 
-	int destx, desty;
 	int srcr, srcg, srcb, srca, destr, destg, destb, desta, finalr, finalg, finalb, finala;
 	unsigned int col;
 	int ycount = 0;
@@ -623,18 +631,19 @@ void AGSBlend::DrawAdd(ScriptMethodParams &params) {
 	if (x < 0) startx = -1 * x;
 	if (y < 0) starty = -1 * y;
 
-	for (ycount = starty; ycount < srcHeight; ycount ++) {
+	int srcy = starty * srcPitch;
+	int desty = (starty + y) * destPitch;
+	for (ycount = starty; ycount < srcHeight; ycount ++, srcy += srcPitch, desty += destPitch) {
 		for (xcount = startx; xcount < srcWidth; xcount ++) {
-			destx = xcount + x;
-			desty = ycount + y;
+			int destx = xcount + x;
 
-			srca = (geta32(srclongbuffer[ycount][xcount]));
+			srca = (geta32(srclongbuffer[srcy + xcount]));
 
 			if (srca != 0) {
-				srcr =  getr32(srclongbuffer[ycount][xcount]) * srca / 255 * scale;
-				srcg =  getg32(srclongbuffer[ycount][xcount]) * srca / 255 * scale;
-				srcb =  getb32(srclongbuffer[ycount][xcount]) * srca / 255 * scale;
-				desta =  geta32(destlongbuffer[desty][destx]);
+				srcr =  getr32(srclongbuffer[srcy + xcount]) * srca / 255 * scale;
+				srcg =  getg32(srclongbuffer[srcy + xcount]) * srca / 255 * scale;
+				srcb =  getb32(srclongbuffer[srcy + xcount]) * srca / 255 * scale;
+				desta =  geta32(destlongbuffer[desty + destx]);
 
 				if (desta == 0) {
 					destr = 0;
@@ -642,9 +651,9 @@ void AGSBlend::DrawAdd(ScriptMethodParams &params) {
 					destb = 0;
 
 				} else {
-					destr =  getr32(destlongbuffer[desty][destx]);
-					destg =  getg32(destlongbuffer[desty][destx]);
-					destb =  getb32(destlongbuffer[desty][destx]);
+					destr =  getr32(destlongbuffer[desty + destx]);
+					destg =  getg32(destlongbuffer[desty + destx]);
+					destb =  getb32(destlongbuffer[desty + destx]);
 				}
 
 				finala = 255 - (255 - srca) * (255 - desta) / 255;
@@ -652,7 +661,7 @@ void AGSBlend::DrawAdd(ScriptMethodParams &params) {
 				finalg = CLIP(srcg + destg, 0, 255);
 				finalb = CLIP(srcb + destb, 0, 255);
 				col = makeacol32(finalr, finalg, finalb, finala);
-				destlongbuffer[desty][destx] = col;
+				destlongbuffer[desty + destx] = col;
 			}
 		}
 	}
@@ -682,16 +691,17 @@ void AGSBlend::DrawAlpha(ScriptMethodParams &params) {
 		return;
 	}
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer;
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint32 *srclongbuffer = (uint32 *)srccharbuffer;
+	int srcPitch = _engine->GetBitmapPitch(src) / 4;
 
-	unsigned char **destcharbuffer = _engine->GetRawBitmapSurface(dest);
-	unsigned int **destlongbuffer = (unsigned int **)destcharbuffer;
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
+	uint32 *destlongbuffer = (uint32 *)destcharbuffer;
+	int destPitch = _engine->GetBitmapPitch(dest) / 4;
 
 	if (srcWidth + x > destWidth) srcWidth = destWidth - x - 1;
 	if (srcHeight + y > destHeight) srcHeight = destHeight - y - 1;
 
-	int destx, desty;
 	int srcr, srcg, srcb, srca, destr, destg, destb, desta, finalr, finalg, finalb, finala;
 
 	int ycount = 0;
@@ -703,29 +713,30 @@ void AGSBlend::DrawAlpha(ScriptMethodParams &params) {
 	if (x < 0) startx = -1 * x;
 	if (y < 0) starty = -1 * y;
 
-	for (ycount = starty; ycount < srcHeight; ycount ++) {
+	int srcy = starty * srcPitch;
+	int desty = (starty + y) * destPitch;
+	for (ycount = starty; ycount < srcHeight; ycount ++, srcy += srcPitch, desty += destPitch) {
 		for (xcount = startx; xcount < srcWidth; xcount ++) {
-			destx = xcount + x;
-			desty = ycount + y;
+			int destx = xcount + x;
 
-			srca = (geta32(srclongbuffer[ycount][xcount])) * trans / 100;
+			srca = (geta32(srclongbuffer[srcy + xcount])) * trans / 100;
 
 			if (srca != 0) {
-				srcr =  getr32(srclongbuffer[ycount][xcount]);
-				srcg =  getg32(srclongbuffer[ycount][xcount]);
-				srcb =  getb32(srclongbuffer[ycount][xcount]);
+				srcr =  getr32(srclongbuffer[srcy + xcount]);
+				srcg =  getg32(srclongbuffer[srcy + xcount]);
+				srcb =  getb32(srclongbuffer[srcy + xcount]);
 
-				destr =  getr32(destlongbuffer[desty][destx]);
-				destg =  getg32(destlongbuffer[desty][destx]);
-				destb =  getb32(destlongbuffer[desty][destx]);
-				desta =  geta32(destlongbuffer[desty][destx]);
+				destr =  getr32(destlongbuffer[desty + destx]);
+				destg =  getg32(destlongbuffer[desty + destx]);
+				destb =  getb32(destlongbuffer[desty + destx]);
+				desta =  geta32(destlongbuffer[desty + destx]);
 
 				finala = 255 - (255 - srca) * (255 - desta) / 255;
 				finalr = srca * srcr / finala + desta * destr * (255 - srca) / finala / 255;
 				finalg = srca * srcg / finala + desta * destg * (255 - srca) / finala / 255;
 				finalb = srca * srcb / finala + desta * destb * (255 - srca) / finala / 255;
 
-				destlongbuffer[desty][destx] = makeacol32(finalr, finalg, finalb, finala);
+				destlongbuffer[desty + destx] = makeacol32(finalr, finalg, finalb, finala);
 			}
 		}
 	}
diff --git a/engines/ags/plugins/ags_creditz/ags_creditz2.cpp b/engines/ags/plugins/ags_creditz/ags_creditz2.cpp
index 5ab3911a52..9f483ea884 100644
--- a/engines/ags/plugins/ags_creditz/ags_creditz2.cpp
+++ b/engines/ags/plugins/ags_creditz/ags_creditz2.cpp
@@ -443,20 +443,24 @@ void AGSCreditz2::draw() {
 void AGSCreditz2::makeMask(int sequence) {
 	int32 wid, hei, cold;
 	int32 x, y;
-	unsigned char **Bitmap, **Bitmap2, **Bitmap3;
+	uint8 *Bitmap, *Bitmap2, *Bitmap3;
 
 	_engine->GetBitmapDimensions(_state->_maskScreen, &wid, &hei, &cold);
 	Bitmap = _engine->GetRawBitmapSurface(_state->_maski);
 	Bitmap2 = _engine->GetRawBitmapSurface(_state->_maskScreen);
 	Bitmap3 = _engine->GetRawBitmapSurface(_state->_creditScreen);
 
+	uint32 Pitch = _engine->GetBitmapPitch(_state->_maski);
+	uint32 Pitch2 = _engine->GetBitmapPitch(_state->_maskScreen);
+	uint32 Pitch3 = _engine->GetBitmapPitch(_state->_creditScreen);
+
 	// Top Mask
 	{
 		x = y = 0;
 		while (y <= _state->_seqSettings[sequence].topmask) {
 			_engine->PollSystem();
 			while (x < wid) {
-				drawPixel(Bitmap, x, y, 15, wid, hei, cold);
+				drawPixel(Bitmap, x, y, 15, Pitch, cold);
 				x++;
 			}
 
@@ -471,7 +475,7 @@ void AGSCreditz2::makeMask(int sequence) {
 	while (y < _state->_seqSettings[sequence].bottommask) {
 		_engine->PollSystem();
 		while (x < wid) {
-			drawPixel(Bitmap, x, y, getPixelColor(Bitmap3, x, y, wid, hei, cold), wid, hei, cold);
+			drawPixel(Bitmap, x, y, getPixelColor(Bitmap3, x, y, Pitch3, cold), Pitch, cold);
 			x++;
 		}
 
@@ -486,7 +490,7 @@ void AGSCreditz2::makeMask(int sequence) {
 		while (y < hei) {
 			_engine->PollSystem();
 			while (x < wid) {
-				drawPixel(Bitmap, x, y, getPixelColor(Bitmap2, x, y, wid, hei, cold), wid, hei, cold);
+				drawPixel(Bitmap, x, y, getPixelColor(Bitmap2, x, y, Pitch2, cold), Pitch, cold);
 				x++;
 			}
 
diff --git a/engines/ags/plugins/ags_creditz/drawing.h b/engines/ags/plugins/ags_creditz/drawing.h
index f35e2f683b..821763f37c 100644
--- a/engines/ags/plugins/ags_creditz/drawing.h
+++ b/engines/ags/plugins/ags_creditz/drawing.h
@@ -31,14 +31,31 @@ namespace AGSCreditz {
 
 class Drawing {
 public:
-	static void drawPixel(unsigned char **Row, int32 x, int32 y,
-		uint col, int32 wid, int32 hei, int32 coldepth) {
-		// TODO
+	static void drawPixel(uint8 *bitmap, int32 x, int32 y,
+		uint col, int32 pitch, int32 coldepth) {
+		switch (coldepth) {
+		case 8:
+			bitmap[x + y * pitch] = col;
+			break;
+		case 16:
+			*((uint16*)(bitmap + y * pitch + x * 2)) = col;
+			break;
+		case 32:
+			*((uint32*)(bitmap + y * pitch + x * 4)) = col;
+			break;
+		}
 	}
 
-	static uint getPixelColor(unsigned char **Row, int32 x, int32 y,
-		int32 wid, int32 hei, int32 coldepth) {
-		// TODO
+	static uint getPixelColor(uint8 *bitmap, int32 x, int32 y,
+		int32 pitch, int32 coldepth) {
+		switch (coldepth) {
+		case 8:
+			return bitmap[x + y * pitch];
+		case 16:
+			return *((uint16*)(bitmap + y * pitch + x * 2));
+		case 32:
+			return *((uint32*)(bitmap + y * pitch + x * 4));
+		}
 		return 0;
 	}
 };
diff --git a/engines/ags/plugins/ags_flashlight/ags_flashlight.cpp b/engines/ags/plugins/ags_flashlight/ags_flashlight.cpp
index 8581087ed6..8e548c9147 100644
--- a/engines/ags/plugins/ags_flashlight/ags_flashlight.cpp
+++ b/engines/ags/plugins/ags_flashlight/ags_flashlight.cpp
@@ -220,7 +220,7 @@ inline unsigned long AGSFlashlight::_blender_alpha16_bgr(unsigned long y) {
 	return ((result & 0xFFFF) | (result >> 16));
 }
 
-inline void AGSFlashlight::setPixel(int x, int y, int color, unsigned int *pixel) {
+inline void AGSFlashlight::setPixel(int x, int y, int color, uint32 *pixel) {
 	if ((x >= g_DarknessDiameter) || (y >= g_DarknessDiameter) || (x < 0) || (y < 0))
 		return;
 
@@ -228,7 +228,7 @@ inline void AGSFlashlight::setPixel(int x, int y, int color, unsigned int *pixel
 }
 
 void AGSFlashlight::plotCircle(int xm, int ym, int r, unsigned int color) {
-	unsigned int *pixel = *(unsigned int **)_engine->GetRawBitmapSurface(g_LightBitmap);
+	uint32 *pixel = (uint32 *)_engine->GetRawBitmapSurface(g_LightBitmap);
 
 	int x = -r;
 	int y = 0;
@@ -267,8 +267,8 @@ void AGSFlashlight::ClipToRange(int &variable, int min, int max) {
 }
 
 void AGSFlashlight::AlphaBlendBitmap() {
-	unsigned short *destpixel = *(unsigned short **)_engine->GetRawBitmapSurface(_engine->GetVirtualScreen());
-	unsigned int *sourcepixel = *(unsigned int **)_engine->GetRawBitmapSurface(g_LightBitmap);
+	uint16 *destpixel = (uint16 *)_engine->GetRawBitmapSurface(_engine->GetVirtualScreen());
+	uint32 *sourcepixel = (uint32 *)_engine->GetRawBitmapSurface(g_LightBitmap);
 
 	unsigned short *currentdestpixel = destpixel;
 	unsigned int *currentsourcepixel = sourcepixel;
@@ -304,7 +304,7 @@ void AGSFlashlight::AlphaBlendBitmap() {
 void AGSFlashlight::DrawTint() {
 	int x, y;
 	BITMAP *screen = _engine->GetVirtualScreen();
-	unsigned short *destpixel = *(unsigned short **)_engine->GetRawBitmapSurface(screen);
+	uint16 *destpixel = (uint16 *)_engine->GetRawBitmapSurface(screen);
 
 	int32 red, blue, green, alpha;
 
@@ -348,7 +348,7 @@ void AGSFlashlight::DrawDarkness() {
 	int x, y;
 	unsigned int color = (255 - (int)((float)g_DarknessLightLevel * 2.55f)) << 24;
 	BITMAP *screen = _engine->GetVirtualScreen();
-	unsigned short *destpixel = *(unsigned short **)_engine->GetRawBitmapSurface(screen);
+	uint16 *destpixel = (uint16 *)_engine->GetRawBitmapSurface(screen);
 	unsigned short *currentpixel;
 
 	calc_x_n(color);
@@ -427,7 +427,7 @@ void AGSFlashlight::CreateLightBitmap() {
 
 	// Fill with darkness color.
 	unsigned int color = (255 - (int)((float)g_DarknessLightLevel * 2.55f)) << 24;
-	unsigned int *pixel = *(unsigned int **)_engine->GetRawBitmapSurface(g_LightBitmap);
+	uint32 *pixel = (uint32 *)_engine->GetRawBitmapSurface(g_LightBitmap);
 
 	int i;
 	for (i = 0; i < g_DarknessDiameter * g_DarknessDiameter; i++)
diff --git a/engines/ags/plugins/ags_flashlight/ags_flashlight.h b/engines/ags/plugins/ags_flashlight/ags_flashlight.h
index 5b048ecada..ae615747b2 100644
--- a/engines/ags/plugins/ags_flashlight/ags_flashlight.h
+++ b/engines/ags/plugins/ags_flashlight/ags_flashlight.h
@@ -78,7 +78,7 @@ private:
 	 */
 	static inline unsigned long _blender_alpha16_bgr(unsigned long y);
 	static inline void calc_x_n(unsigned long x);
-	static inline void setPixel(int x, int y, int color, unsigned int *pixel);
+	static inline void setPixel(int x, int y, int color, uint32 *pixel);
 	static void plotCircle(int xm, int ym, int r, unsigned int color);
 	static void ClipToRange(int &variable, int min, int max);
 	static void AlphaBlendBitmap();
diff --git a/engines/ags/plugins/ags_pal_render/ags_pal_render.cpp b/engines/ags/plugins/ags_pal_render/ags_pal_render.cpp
index b48ca2cb23..146d6443e6 100644
--- a/engines/ags/plugins/ags_pal_render/ags_pal_render.cpp
+++ b/engines/ags/plugins/ags_pal_render/ags_pal_render.cpp
@@ -1,1791 +1,1828 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or(at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "ags/lib/allegro.h"
-#include "ags/plugins/ags_pal_render/ags_pal_render.h"
-#include "ags/plugins/ags_pal_render/pal_render.h"
-#include "ags/plugins/ags_pal_render/raycast.h"
-#include "ags/ags.h"
-
-namespace AGS3 {
-namespace Plugins {
-namespace AGSPalRender {
-
-#define MAX_OVERLAYS 128
-#define MAX_STARS 1024
-#define MAX_DEPTH 64
-
-#define PI         (3.1415926535f)
-#define HALF_PI    (0.5f * PI)
-#define TWO_PI     (2.0f * PI)
-#define TWO_PI_INV (1.0f / TWO_PI)
-
-const float halfpi = (0.5f * PI);
-const float twopi  = (2.0f * PI);
-const float twopi_inv = (1.0f / TWO_PI);
-const float pisquared = PI * PI;
-const float picubed = PI * PI * PI;
-
-IAGSEngine *engine;
-
-//unsigned char clut[256][256];
-unsigned char clut[65536];
-
-struct transoverlaytype {
-	int sprite;
-	int spritemask;
-	int blendtype;
-	int x;
-	int y;
-	int trans;
-	int level;
-	bool enabled;
-} overlay[MAX_OVERLAYS];
-
-int clutslot;
-int drawreflections;
-byte cycle_remap[256];
-
-struct starstype {
-	float x;
-	float y;
-	float z;
-	unsigned char color;
-	long sprite;
-	int maxrad;
-	int scaleboost;
-};
-starstype *stars;
-
-struct starsoptions {
-	float speed;
-	int maxstars;
-	int depthmultiplier;
-	int originx;
-	int originy;
-	int overscan;
-} Starfield;
-long *reflectionmap;
-BITMAP *rcolormap;
-BITMAP *ralphamap;
-
-struct charrefopt {
-	char reflect;
-	int replaceview;
-};
-
-struct objrefopt {
-	char reflect;
-	char ignorescaling;
-};
-
-struct reflectionopt {
-	charrefopt *Characters;
-	objrefopt *Objects;
-	int blendslot;
-	int blendamount;
-} Reflection;
-
-int dummy;
-
-#define LENS_WIDTH 150
-
-struct LensDistort {
-	int xoffset;
-	int yoffset;
-};
-
-LensDistort *lens;
-struct LensOpt {
-	bool draw;
-	int lenswidth;
-	int lenszoom;
-	int level;
-	int x;
-	int y;
-	int clampoffset;
-} LensOption;
-
-const int alphamultiply [4096] = {
-//#include "alphamultiply.txt"
-};
-float rot_sine_LUT[360];
-float rot_cos_LUT[360];
-
-BITMAP *backgroundimage;
-
-PALSTRUCT objectivepal[256];
-int bgimgspr;
-
-void WriteObjectivePalette(unsigned char index, unsigned char r, unsigned char b, unsigned char g) {
-	objectivepal[index].r = r;
-	objectivepal[index].b = b;
-	objectivepal[index].g = g;
-}
-
-int ReadObjectivePaletteR(unsigned char index) {
-	return objectivepal[index].r;
-}
-
-int ReadObjectivePaletteB(unsigned char index) {
-	return objectivepal[index].b;
-}
-int ReadObjectivePaletteG(unsigned char index) {
-	return objectivepal[index].g;
-}
-
-
-#define SQRT_MAGIC_F 0x5f3759df
-float  q3sqrt(const float x) {
-	const float xhalf = 0.5f * x;
-
-	union { // get bits for floating value
-		float x;
-		int i;
-	} u;
-	u.x = x;
-	u.i = SQRT_MAGIC_F - (u.i >> 1);  // gives initial guess y0
-	return x * u.x * (1.5f - xhalf * u.x * u.x); // Newton step, repeating increases accuracy
-}
-
-void Make_Sin_Lut() {
-	for (int angle = 0; angle < 360; angle++) {
-		double rad = (angle * PI) / 180.0;
-		rot_sine_LUT [angle] = static_cast<float>(sin(rad));
-		rot_cos_LUT [angle]  = static_cast<float>(cos(rad));
-	}
-}
-
-/*
-void PreMultiply_Alphas () //Ha ha, this isn't the kind of premultiplcation you're thinking of.
-{
-    for (int y=0;y<64;y++)
-        for (int x=0;x<64;x++)
-            alphamultiply [y*64+x] = y*x;
-}
-*/
-
-int GetModifiedBackgroundImage() {
-	return bgimgspr;
-}
-
-unsigned short root(unsigned short x) {
-	unsigned short a, b;
-	b = x;
-	a = x = 0x3f;
-	x = b / x;
-	a = x = (x + a) >> 1;
-	x = b / x;
-	a = x = (x + a) >> 1;
-	x = b / x;
-	x = (x + a) >> 1;
-	return (x);
-}
-
-
-float Hill(float x) {
-	const float a0 = 1.0f;
-	const float a2 = 2.0f / PI - 12.0f / (pisquared);
-	const float a3 = 16.0f / (picubed) - 4.0f / (pisquared);
-	const float xx = x * x;
-	const float xxx = xx * x;
-
-	return a0 + a2 * xx + a3 * xxx;
-}
-
-float FastSin(float x) {
-	// wrap x within [0, TWO_PI)
-	const float a = x * twopi_inv;
-	x -= static_cast<int>(a) * twopi;
-	if (x < 0.0f)
-		x += twopi;
-
-	// 4 pieces of hills
-	if (x < halfpi)
-		return Hill(halfpi - x);
-	else if (x < PI)
-		return Hill(x - halfpi);
-	else if (x < 3.0f * halfpi)
-		return -Hill(3.0f * halfpi - x);
-	else
-		return -Hill(x - 3.0f * halfpi);
-}
-
-float FastCos(float x) {
-	return FastSin(x + halfpi);
-}
-
-FLOAT_RETURN_TYPE AGSFastSin(SCRIPT_FLOAT(x)) {
-	INIT_SCRIPT_FLOAT(x);
-	x = FastSin(x);
-	RETURN_FLOAT(x);
-}
-
-FLOAT_RETURN_TYPE AGSFastCos(SCRIPT_FLOAT(x)) {
-	INIT_SCRIPT_FLOAT(x);
-	x = FastSin(x + halfpi);
-	RETURN_FLOAT(x);
-}
-
-
-void DrawLens(int ox, int oy) {
-	int32 sh, sw = 0;
-	engine->GetScreenDimensions(&sw, &sh, nullptr);
-	BITMAP *virtsc = engine->GetVirtualScreen();
-	if (!virtsc) engine->AbortGame("DrawLens: Cannot get virtual screen.");
-	BITMAP *lenswrite = engine->CreateBlankBitmap(LensOption.lenswidth, LensOption.lenswidth, 8);
-	unsigned char **vScreen = engine->GetRawBitmapSurface(virtsc);
-	unsigned char **lensarray = engine->GetRawBitmapSurface(lenswrite);
-	int radius = LensOption.lenswidth >> 1;
-	for (int y = 0; y < LensOption.lenswidth; y++) {
-		int ypos = y * LensOption.lenswidth;
-		for (int x = 0; x < LensOption.lenswidth; x++) {
-			int lenspos = ypos + x;
-			int coffx = lens[lenspos].xoffset;
-			int coffy = lens[lenspos].yoffset;
-			if (oy + coffy > 0 && oy + coffy < sh && ox + coffx > 0 && ox + coffx < sw) {
-				lensarray[y][x] = vScreen[oy + coffy][ox + coffx];
-				//vScreen[oy+coffy][ox+coffx] = ABS(coffy);
-			}
-		}
-	}
-	/*
-	for (int y=0;y<LensOption.lenswidth;y++)
-	{
-	    int ypos = y*LensOption.lenswidth;
-	    for (int x=0;x<LensOption.lenswidth;x++)
-	    {
-	        if (oy+y > 0 && oy+y < sh && ox+x > 0 && ox+x < sw)
-	        {
-	            vScreen[oy+y][ox+x] = lensarray[y][x];
-	        }
-	    }
-	}
-	*/
-	int radsq = radius * radius;
-	for (int cy = -radius; cy <= radius; cy++) { //Draw a circle around the point, for the mask.
-		int cysq = cy * cy;
-		for (int cx = -radius; cx <= radius; cx++) {
-			int cxsq = cx * cx;
-			int dx = cx + ox;
-			int dy = cy + oy;
-			if ((cxsq + cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0 && cy + radius < LensOption.lenswidth - 1 && cx + radius < LensOption.lenswidth - 1) {
-				//if (cy+radius < 0 || cx+radius < 0) engine->AbortGame ("I did something wrong");
-				vScreen[dy][dx] = lensarray[cy + radius][cx + radius];
-			}
-		}
-	}
-
-	engine->ReleaseBitmapSurface(lenswrite);
-	engine->ReleaseBitmapSurface(virtsc);
-	engine->FreeBitmap(lenswrite);
-}
-
-void SetLensPos(int x, int y) {
-	LensOption.x = x;
-	LensOption.y = y;
-}
-
-int GetLensX() {
-	return LensOption.x;
-}
-
-int GetLensY() {
-	return LensOption.y;
-}
-
-void SetLensDrawn(int toggle) {
-	if (toggle > 0) LensOption.draw = 1;
-	else LensOption.draw = 0;
-}
-
-int GetLensDrawn() {
-	return LensOption.draw;
-}
-
-void SetLensOffsetClamp(int clamp) {
-	if (clamp < 0) LensOption.clampoffset = LensOption.lenswidth;
-	else LensOption.clampoffset = clamp;
-}
-
-int GetLensOffsetClamp() {
-	return LensOption.clampoffset;
-}
-
-int GetLensLevel() {
-	return LensOption.level;
-}
-
-void SetLensLevel(int level) {
-	if (level < 0 || level > 4) engine->AbortGame("SetLensLevel: Invalid level.");
-	else LensOption.level = level;
-}
-
-void LensInitialize(int width, int zoom, int lensx, int lensy, int level, int clamp = -1) {
-	int32 sw, sh, radius;
-	if (width < 1) engine->AbortGame("Invalid lens dimension!");
-	radius = width >> 1;
-	lens = new LensDistort [width * width]();
-	engine->GetScreenDimensions(&sw, &sh, nullptr);
-	int radsq = radius * radius;
-	int zoomsq = zoom * zoom;
-	for (int y = 0; y < radius; y++) {
-		int ysq = y * y;
-		for (int x = 0; x < radius; x++) {
-			int lx, ly;
-			int xsq = x * x;
-			if ((xsq + ysq) < (radsq)) {
-				float shift = zoom / sqrt((float)(zoomsq - (xsq + ysq - radsq)));
-				lx = (int)(x * shift - x);
-				ly = (int)(y * shift - y);
-			} else {
-				lx = 0;
-				ly = 0;
-			}
-			lens[(radius - y)*width + (radius - x)].xoffset =  lx;
-			lens[(radius - y)*width + (radius - x)].yoffset =  ly;
-			lens[(radius + y)*width + (radius + x)].xoffset = -lx;
-			lens[(radius + y)*width + (radius + x)].yoffset = -ly;
-			lens[(radius + y)*width + (radius - x)].xoffset =  lx;
-			lens[(radius + y)*width + (radius - x)].yoffset = -ly;
-			lens[(radius - y)*width + (radius + x)].xoffset = -lx;
-			lens[(radius - y)*width + (radius + x)].yoffset =  ly;
-		}
-	}
-	LensOption.lenswidth = width;
-	LensOption.lenszoom = zoom;
-	if (clamp < 0) LensOption.clampoffset = width;
-	else LensOption.clampoffset = clamp;
-	LensOption.x = lensx;
-	LensOption.y = lensy;
-	if (level < 0 || level > 4) engine->AbortGame("SetLensLevel: Invalid level.");
-	else LensOption.level = level;
-}
-
-void ResetRemapping() {
-	for (int j = 0; j < 256; ++j) {
-		cycle_remap [j] = j;
-	}
-}
-
-#define MAX_PLASMA_COMPLEXITY 4
-int plasmatype[MAX_PLASMA_COMPLEXITY];
-int plasmadata [MAX_PLASMA_COMPLEXITY];
-int plasmadata2 [MAX_PLASMA_COMPLEXITY];
-int plasmadata3 [MAX_PLASMA_COMPLEXITY];
-int plasmaroottype;
-
-
-void SetPlasmaRootType(int real) {
-	if (real) plasmaroottype = 1;
-	else plasmaroottype = 0;
-}
-
-int GetPlasmaRootType() {
-	return plasmaroottype;
-}
-
-void SetPlasmaType(int component, int type, int data, int data2, int data3) {
-	if (component >= MAX_PLASMA_COMPLEXITY) engine->AbortGame("Plasma too complex!");
-	else {
-		plasmatype [component] = type;
-		plasmadata [component] = data;
-		plasmadata2[component] = data2;
-		plasmadata3[component] = data3;
-	}
-
-	//0 = None.
-	//1 = Horizontal Bars (data=width)
-	//2 = Vertical Bars (data=width)
-	//3 = Circle (data=x,data2=y,data3=width)
-	//4 = Diagonal Bars (data=width)
-}
-
-void ResetPlasmaSettings() {
-	int i = 0;
-	while (i < MAX_PLASMA_COMPLEXITY) {
-		plasmatype [i] = 0;
-		plasmadata [i] = 0;
-		plasmadata2[i] = 0;
-		plasmadata3[i] = 0;
-		i++;
-	}
-}
-
-void DrawPlasma(int slot, int palstart, int palend) {
-	BITMAP *plasmaspr = engine->GetSpriteGraphic(slot);
-	if (!plasmaspr) engine->AbortGame("Plasma: Not a sprite I can load.");
-	int32 w, h, basecol, range = 0;
-	if (palend > palstart) {
-		range = palend - palstart;
-		basecol = palstart;
-	} else {
-		range = palstart - palend;
-		basecol = palend;
-	}
-	engine->GetBitmapDimensions(plasmaspr, &w, &h, nullptr);
-	unsigned char **plasmarray = engine->GetRawBitmapSurface(plasmaspr);
-	double frange = range / 2.0;
-	int complex = 0;
-	int color = 0;
-	int i = 0;
-	while (i < MAX_PLASMA_COMPLEXITY) {
-		if (plasmatype[i] > 0) complex++;
-		i++;
-	}
-	for (int x = 0; x < w; x++) {
-		for (int y = 0; y < h; y++) {
-			color = 0;
-			for (int p = 0; p < MAX_PLASMA_COMPLEXITY; p++) {
-				if (plasmatype[p] == 1) { //1 = Horizontal Bars (data=width)
-					color += int(frange + (frange * FastSin(y / (float)plasmadata[p])));
-				} else if (plasmatype[p] == 2) { //2 = Vertical Bars (data=width)
-					color += int(frange + (frange * FastSin(x / (float)plasmadata[p])));
-				} else if (plasmatype[p] == 3) { //3 = Circle (data=x,data2=y,data3=width)
-					int cx, cy = 0;
-					cx = plasmadata [p];
-					cy = plasmadata2 [p];
-					if (plasmaroottype == 1) color += int(frange + (frange * FastSin(q3sqrt((float)((x - cx) * (x - cx) + (y - cy) * (y - cy)) / plasmadata3[p]))));
-					else color += int(frange + (frange * FastSin(root(((x - cx) * (x - cx) + (y - cy) * (y - cy)) / plasmadata3[p]))));
-				} else if (plasmatype[p] == 4) { //4 = Diagonal Bars (data=width)
-					color += int(frange + (frange * FastSin((x + y) / (float)plasmadata[p])));
-				}
-			}
-			if (color > 0 && complex > 0) color = color / complex;
-			plasmarray[y][x] = static_cast<unsigned char>(basecol + color);
-		}
-	}
-	engine->ReleaseBitmapSurface(plasmaspr);
-	engine->NotifySpriteUpdated(slot);
-}
-
-void DoFire(int spriteId, int masksprite, int palstart, int palend, int strength, int seed, int cutoff, int windspeed) {
-	BITMAP *firespr = engine->GetSpriteGraphic(masksprite);
-	BITMAP *firecolorspr = engine->GetSpriteGraphic(spriteId);
-	BITMAP *seedspr;
-	int32 w, h = 0;
-	int range, basecol, dir = 0;
-	if (palend > palstart) {
-		range = palend - palstart;
-		basecol = palstart;
-		dir = 1;
-	} else {
-		range = palstart - palend;
-		basecol = palend;
-		dir = -1;
-	}
-	int divider = 256 / range;
-	engine->GetBitmapDimensions(firespr, &w, &h, nullptr);
-	unsigned char **fire = engine->GetRawBitmapSurface(firespr);
-	unsigned char **color = engine->GetRawBitmapSurface(firecolorspr);
-	int sparky = 0;
-	//srand(time(NULL));
-	for (int y = 0; y < h - 1; y++) {
-		if ((int)::AGS::g_vm->getRandomNumber(9) > 7 - windspeed) { //Wind right
-			for (int x = w - 1; x > 1; x--) {
-				fire[y][x] = fire[y][x - 1];
-			}
-		} else if ((int)::AGS::g_vm->getRandomNumber(9) > 7 + windspeed) { // wind left
-			for (int x = 0; x < w - 1; x++) {
-				fire[y][x] = fire[y][x + 1];
-			}
-		}
-	}
-	for (int x = 0; x < w; x++) {
-		sparky = ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % (h - 2));
-		if (sparky < h && sparky > 0 && fire[h - sparky][x] > cutoff &&
-				ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % 10) > 7)
-			fire[h - sparky][x] = 255;
-		sparky = ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % (h - 2));
-		if (sparky < h && sparky > 0 && fire[h - sparky][x] > cutoff &&
-				ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % 10) > 7)
-			fire[h - sparky][x] = 0;
-	}
-	if (seed == 0) {
-		for (int x = 0; x < w; x++)
-			fire[h - 1][x] = 255;
-		for (int x = 0; x < w; x++)
-			fire[h - 2][x] = ::AGS::g_vm->getRandomNumber(255);
-	} else if (seed > 0) {
-		seedspr = engine->GetSpriteGraphic(seed);
-		BITMAP *virtsc = engine->GetVirtualScreen();
-		engine->SetVirtualScreen(firespr);
-		engine->BlitBitmap(0, 0, seedspr, 1);
-		engine->SetVirtualScreen(virtsc);
-		engine->ReleaseBitmapSurface(virtsc);
-		engine->ReleaseBitmapSurface(seedspr);
-		engine->NotifySpriteUpdated(spriteId);
-		engine->NotifySpriteUpdated(masksprite);
-	}
-
-	for (int y = 0; y < h - 1; y++) {
-		for (int x = 0; x < w; x++) {
-			fire[y][x] =
-			    ((fire[(y + 1) % h][(x - 1 + w) % w]
-			      + fire[(y + 1) % h][(x) % w]
-			      + fire[(y + 1) % h][(x + 1) % w]
-			      + fire[(y + 2) % h][(x) % w])
-			     * 100) / (400 + (100 - strength));
-			if (fire[y][x] < cutoff) fire[y][x] = 0;
-			//if (fire[y][x] ==255) color [y][x] = palend;
-			else color [y][x] = static_cast<unsigned char>(basecol + (fire[y][x] / divider) * dir);
-		}
-	}
-	engine->ReleaseBitmapSurface(firespr);
-	engine->ReleaseBitmapSurface(firecolorspr);
-	engine->NotifySpriteUpdated(spriteId);
-	engine->NotifySpriteUpdated(masksprite);
-}
-
-/*
-unsigned char MixColorAlpha (unsigned char fg,unsigned char bg,unsigned char alpha)
-{
-    //unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
-    //unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
-    //BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
-    //if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
-    //unsigned char **clutarray = engine->GetRawBitmapSurface (clutspr);
-    AGSColor *palette = engine->GetPalette ();
-    int i=0;
-    int out_r = (palette[fg].r>>1) * alpha + (palette[bg].r>>1) * (255 - alpha);
-    int out_g = palette[fg].g * alpha + palette[bg].g * (255 - alpha);
-    int out_b = (palette[fg].b>>1) * alpha + (palette[bg].b>>1) * (255 - alpha);
-    //unsigned char ralpha = alpha>>2;
-    //unsigned char invralpha = 64-ralpha;
-    //if (ralpha > alpha) engine->AbortGame ("wtf");
-    //int out_r = alphamultiply[(palette[fg].r>>1)][ralpha] + alphamultiply[(palette[bg].r>>1)][(invralpha)];
-    //int out_g = alphamultiply[(palette[fg].g)][ralpha] + alphamultiply[(palette[bg].g)][(invralpha)];
-    //int out_b = alphamultiply[(palette[fg].b>>1)][ralpha] + alphamultiply[(palette[bg].b>>1)][(invralpha)];
-    out_r = (out_r + 1 + (out_r >> 8)) >> 8;
-    out_g = (out_g + 1 + (out_g >> 8)) >> 8;
-    out_b = (out_b + 1 + (out_b >> 8)) >> 8;
-    i = ((out_r << 11) | (out_g << 5) | out_b);
-    unsigned char (*clutp) = clut;
-    //unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
-    unsigned char result = cycle_remap [*(clutp+i)]; //Once again, to make sure that the palette slot used is the right one.
-    //engine->ReleaseBitmapSurface (clutspr);
-    return result;
-}
-
-unsigned char MixColorAdditive (unsigned char fg,unsigned char bg,unsigned char alpha)
-{
-    //unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
-    //unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
-    //BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
-    //if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
-    //unsigned char **clutarray = engine->GetRawBitmapSurface (clutspr);
-    AGSColor *palette = engine->GetPalette ();
-    int i=0;
-    int add_r,add_b,add_g = 0;
-    char ralpha = alpha>>2;
-    //if (ralpha > alpha) engine->AbortGame ("wtf");
-    //add_r = (((palette[fg].r>>1) * (alpha))>>8);
-    //add_b = (((palette[fg].b>>1) * (alpha))>>8);
-    //add_g = (((palette[fg].g)    * (alpha))>>8);
-    add_r = ((alphamultiply[(palette[fg].r>>1)*64+ralpha])>>6);
-    add_b = ((alphamultiply[(palette[fg].b>>1)*64+ralpha])>>6);
-    add_g = ((alphamultiply[(palette[fg].g   )*64+ralpha])>>6);
-    int out_r = min(31,(palette[bg].r>>1) + add_r);
-    int out_g = min(63, palette[bg].g     + add_g);
-    int out_b = min(31,(palette[bg].b>>1) + add_b);
-    i = ((out_r << 11) | (out_g << 5) | out_b);
-    unsigned char (*clutp) = clut;
-    unsigned char result = cycle_remap [*(clutp+i)]; //Once again, to make sure that the palette slot used is the right one.
-    //unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
-    //engine->ReleaseBitmapSurface (clutspr);
-    return result;
-}
-*/
-unsigned char GetColor565(unsigned char r, unsigned char g, unsigned char b) {
-	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
-	//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
-	//unsigned char **clutarray = engine->GetRawBitmapSurface (clutspr);
-	int i = ((r << 11) | (g << 5) | b);
-	unsigned char *clutp = clut;
-	unsigned char result = *(clutp + i);
-	result = cycle_remap [result]; //Once again, to make sure that the palette slot used is the right one.
-	//engine->ReleaseBitmapSurface (clutspr);
-	return result;
-}
-
-void CycleRemap(int start, int end) {
-	if (end > start) {
-		// Rotate left
-		int wraparound = cycle_remap [start];
-		for (; start < end; ++start) {
-			cycle_remap [start] = cycle_remap [start + 1];
-		}
-		cycle_remap [end] = wraparound;
-	} else if (end < start) {
-		// Rotate right
-		int wraparound = cycle_remap [start];
-		for (; start > end; --start) {
-			cycle_remap [start] = cycle_remap [start - 1];
-		}
-		cycle_remap [end] = wraparound;
-
-	}
-}
-
-unsigned char GetRemappedSlot(unsigned char slot) {
-	return cycle_remap [slot];
-}
-
-int LoadCLUT(int slot) {
-	if (engine->GetSpriteWidth(slot) != 256 || engine->GetSpriteHeight(slot) != 256) return 1;
-	BITMAP *clutimage = engine->GetSpriteGraphic(slot);
-	unsigned char **clutarray = engine->GetRawBitmapSurface(clutimage);
-	for (int y = 0; y < 256; y++) {
-		for (int x = 0; x < 256; x++) {
-			clut[y * 256 + x] = clutarray[y][x];
-		}
-	}
-	clutslot = slot;
-	engine->ReleaseBitmapSurface(clutimage);
-	return 0;
-}
-
-void SetReflections(int toggle) {
-	drawreflections = toggle;
-}
-
-int IsReflectionsOn() {
-	return drawreflections;
-}
-
-int GetLuminosityFromPalette(int slot) {
-	AGSColor *pal = engine->GetPalette();
-	int lum = (pal[slot].r +
-	           pal[slot].r +
-	           pal[slot].r +
-	           pal[slot].g +
-	           pal[slot].g +
-	           pal[slot].g +
-	           pal[slot].g +
-	           pal[slot].b) >> 3;
-	return lum;
-}
-
-
-
-void SetStarsOriginPoint(int x, int y) {
-	Starfield.originx = x;
-	Starfield.originy = y;
-}
-void InitializeStars(int slot, int maxstars) {
-	int32 sw, sh = 0;
-	BITMAP *canvas = engine->GetSpriteGraphic(slot);
-	engine->GetBitmapDimensions(canvas, &sw, &sh, nullptr);
-	Starfield.maxstars = maxstars;
-	Starfield.overscan = 20;
-	stars = new starstype [Starfield.maxstars];
-	for (int i = 0; i < Starfield.maxstars; i++) {
-		stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
-		if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
-		stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
-		if (stars[i].y < 1.0 && stars[i].y > -1.0) stars[i].y = (float)sh;
-		stars[i].z = (float)(MAX_DEPTH);
-		stars[i].color = (::AGS::g_vm->getRandomNumber(0x7fffffff) % 240);
-		stars[i].sprite = 0;
-		stars[i].maxrad = (::AGS::g_vm->getRandomNumber(0x7fffffff) % 5);
-	}
-}
-
-void IterateStars(int slot) {
-	long sw, sh = 0;
-	sw = engine->GetSpriteWidth(slot);
-	sh = engine->GetSpriteHeight(slot);
-	for (int i = 0; i < Starfield.maxstars; i++) {
-		stars[i].z -= Starfield.speed;
-		//if (stars[i].z < 1.0) stars[i].z = (double)MAX_DEPTH;
-		float k = Starfield.depthmultiplier / stars[i].z;
-		int px = static_cast<int>(stars[i].x * k + Starfield.originx);
-		int py = static_cast<int>(stars[i].y * k + Starfield.originy);
-		if (px >= sw + Starfield.overscan || px < 0 - Starfield.overscan || py >= sh + Starfield.overscan || py < 0 - Starfield.overscan) {
-			stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
-			if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
-			stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
-			if (stars[i].y < 1.0 && stars[i].y > 1.0) stars[i].y = (float)sh;
-			stars[i].z = (float)MAX_DEPTH;
-			//stars[i].color = (rand () %240);
-		}
-	}
-}
-int GetStarfieldOverscan() {
-	return Starfield.overscan;
-}
-void SetStarfieldOverscan(int overscan) {
-	Starfield.overscan = overscan;
-}
-
-int GetStarfieldOriginX() {
-	return Starfield.originx;
-}
-
-int GetStarfieldOriginY() {
-	return Starfield.originy;
-}
-
-void SetStarfieldDepthMultiplier(int multi) {
-	Starfield.depthmultiplier = multi;
-}
-
-int GetStarfieldDepthMultiplier() {
-	return Starfield.depthmultiplier;
-}
-
-int GetStarfieldMaxStars() {
-	return Starfield.maxstars;
-}
-
-void SetStarSpriteScaleBoost(int star, int boost) {
-	stars[star].scaleboost = boost;
-}
-
-int GetStarSpriteScaleBoost(int star) {
-	return stars[star].scaleboost;
-}
-
-void SetStarMaxRadius(int star, int radius) {
-	stars[star].maxrad = radius;
-}
-
-int GetStarMaxRadius(int star) {
-	return stars[star].maxrad;
-}
-
-void RotateStar(int star, int angle, int px, int py) {
-	float rsin = rot_sine_LUT[angle];
-	float rcos = rot_cos_LUT[angle];
-	float fPx = (float)px;
-	float fPy = (float)py;
-	float x1 = 0, y1 = 0, xRot = 0, yRot = 0;
-	int i = star;
-	x1 = stars[i].x;
-	y1 = stars[i].y;
-	xRot = fPx + rcos * (x1 - fPx) - rsin * (y1 - fPy);
-	yRot = fPy + rsin * (x1 - fPx) + rcos * (y1 - fPy);
-	stars[i].x = xRot;
-	stars[i].y = yRot;
-	i++;
-}
-
-FLOAT_RETURN_TYPE GetStarX(int i) {
-	float starx = (float)stars[i].x;
-	RETURN_FLOAT(starx);
-}
-
-FLOAT_RETURN_TYPE GetStarY(int i) {
-	float stary = (float)stars[i].y;
-	RETURN_FLOAT(stary);
-}
-
-FLOAT_RETURN_TYPE GetStarZ(int i) {
-	float starz = (float)stars[i].z;
-	RETURN_FLOAT(starz);
-}
-
-void SetStarPosition(int star, SCRIPT_FLOAT(x), SCRIPT_FLOAT(y), SCRIPT_FLOAT(z)) {
-	INIT_SCRIPT_FLOAT(x);
-	INIT_SCRIPT_FLOAT(y);
-	INIT_SCRIPT_FLOAT(z);
-	stars[star].x = x;
-	stars[star].y = y;
-	stars[star].z = z;
-}
-
-void SetStarColor(int star, unsigned char color) {
-	stars[star].color = color;
-}
-
-unsigned char GetStarColor(int star) {
-	return stars[star].color;
-}
-
-void SetStarSprite(int star, int slot) {
-	stars[star].sprite = slot;
-}
-
-int GetStarSprite(int star) {
-	return stars[star].sprite;
-}
-
-void SetStarSpriteRange(int start, int end, int slot) {
-	int sfix = start;
-	int efix = end;
-	if (start > Starfield.maxstars) sfix = Starfield.maxstars - 1;
-	if (end > Starfield.maxstars) efix = Starfield.maxstars;
-	for (int i = sfix; i < efix; i++)
-		stars[i].sprite = slot;
-}
-
-void DrawStars(int slot, int maskslot) {
-	int32 sw, sh = 0;
-	BITMAP *canvas = engine->GetSpriteGraphic(slot);
-	if (!canvas) engine->AbortGame("DrawStars: Can't load sprite slot.");
-	BITMAP *maskcanvas = engine->GetSpriteGraphic(maskslot);
-	if (!maskcanvas) engine->AbortGame("DrawStars: Can't load mask slot.");
-	engine->GetBitmapDimensions(canvas, &sw, &sh, nullptr);
-	unsigned char **screenarray = engine->GetRawBitmapSurface(canvas);
-	unsigned char **maskarray = engine->GetRawBitmapSurface(maskcanvas);
-	for (int i = 0; i < Starfield.maxstars; i++) {
-		//stars[i].z-= 0.5;
-		//if (stars[i].z < 1.0) stars[i].z = (double)MAX_DEPTH;
-		float k = (float)Starfield.depthmultiplier / stars[i].z;
-		int px = static_cast<int>(stars[i].x * k + Starfield.originx);
-		int py = static_cast<int>(stars[i].y * k + Starfield.originy);
-		if (px >= sw + Starfield.overscan || px < 0 - Starfield.overscan || py >= sh + Starfield.overscan || py < 0 - Starfield.overscan) {
-			stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
-			if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
-			stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
-			if (stars[i].y < 1.0 && stars[i].y > 1.0) stars[i].y = (float)sh;
-			stars[i].z = (float)MAX_DEPTH;
-			//stars[i].color = (rand () %240);
-		} else if (stars[i].z > 0) {
-			int ivalue = (63 - (int)stars[i].z);
-			if (ivalue > 63) ivalue = 63;
-			else if (ivalue < 0) ivalue = 0;
-			unsigned char value = (unsigned char)(ivalue);
-			unsigned char maskcolor = value << 2;
-			if (stars[i].sprite > 0) {
-				BITMAP *origspr = engine->GetSpriteGraphic(stars[i].sprite);
-				int scale = (ivalue + 1) * 100 >> 6;
-				//int scale = 50;
-				if (scale < 1) scale = 1;
-				/*
-				if (scale != 100)
-				{
-				unsigned char** orig = engine->GetRawBitmapSurface (origspr);
-				int32 h1,h2,w1,w2=0;
-				double fw2,fh2;
-				engine->GetBitmapDimensions (origspr,&w1,&h1,NULL);
-				fh2 = h1 * (scale / 100.0);
-				fw2 = w1 * (scale / 100.0);
-				h2 = static_cast<int>(fh2);
-				w2 = static_cast<int>(fw2);
-				if (w2 < 1) w2 = 1;
-				if (h2 < 1) h2 = 1;
-				resizspr = engine->CreateBlankBitmap (w2,h2,8);
-				unsigned char** resized = engine->GetRawBitmapSurface (resizspr);
-				int x_ratio = (int)((w1<<16)/w2) +1;
-				int y_ratio = (int)((h1<<16)/h2) +1;
-				int x2, y2 ;
-				for (int i=0;i<h2;i++)
-				{
-				    for (int j=0;j<w2;j++)
-				   {
-				       x2 = ((j*x_ratio)>>16) ;
-				       y2 = ((i*y_ratio)>>16) ;
-				       resized [i][j] = orig [y2][x2];
-				 }
-				}
-				engine->ReleaseBitmapSurface (resizspr);
-				}
-				//resizspr = origspr;
-				int32 w,h=0;
-				engine->GetBitmapDimensions (resizspr,&w,&h,NULL);
-				unsigned char **imagemap = engine->GetRawBitmapSurface (resizspr);
-				int ox = px - (w>>1);
-				int oy = py - (h>>1);
-				for (int dy=0;dy<h;dy++)
-				{
-				for (int dx=0;dx<w;dx++)
-				{
-				   int ex = ox+dx;
-				   int ey = oy+dy;
-				   if (ex < sw && ex >= 0 && ey < sh && ey >= 0)
-				   {
-				       if (maskcolor > maskarray [ey][ex] && imagemap[dy][dx] > 0)
-				       {
-				           maskarray [ey][ex] = maskcolor;
-				           screenarray [ey][ex] = imagemap[dy][dx];
-				       }
-				   }
-				}
-				}
-				*/
-
-				unsigned char **orig = engine->GetRawBitmapSurface(origspr);
-				int32 h1, h2, w1, w2 = 0;
-				double fw2, fh2;
-				engine->GetBitmapDimensions(origspr, &w1, &h1, nullptr);
-				fh2 = h1 * (scale / 100.0);
-				fw2 = w1 * (scale / 100.0);
-				h2 = static_cast<int>(fh2);
-				w2 = static_cast<int>(fw2);
-				if (w2 < 1) w2 = 1;
-				if (h2 < 1) h2 = 1;
-				int x_ratio = (int)((w1 << 16) / w2) + 1;
-				int y_ratio = (int)((h1 << 16) / h2) + 1;
-				int x2, y2 ;
-				int ox = px - (w2 >> 1);
-				int oy = py - (h2 >> 1);
-				for (int ii = 0; ii < h2; ii++) {
-					int temprzy = ii * y_ratio;
-					int ey = oy + ii;
-					for (int j = 0; j < w2; j++) {
-						x2 = ((j * x_ratio) >> 16);
-						y2 = ((temprzy) >> 16);
-						int ex = ox + j;
-						if (ex < sw && ex >= 0 && ey < sh && ey >= 0) {
-							if (maskcolor > maskarray [ey][ex] && orig[y2][x2] > 0) {
-								maskarray [ey][ex] = maskcolor;
-								screenarray [ey][ex] = orig[y2][x2];
-							}
-						}
-						//resized [ii][j] = orig [y2][x2];
-					}
-				}
-				engine->ReleaseBitmapSurface(origspr);
-			} else if (stars[i].sprite == 0) {
-				if (stars[i].maxrad == 1) {
-					if (px < sw && px >= 0 && py < sh && py >= 0) {
-						if (maskcolor > maskarray[py][px]) {
-							maskarray[py][px] = maskcolor;
-							screenarray[py][px] = stars[i].color;
-						}
-					}
-				} else {
-					int scale = ((((int)stars[i].z) * 100) / 63);
-					if (scale < 1) scale = 1;
-					int radius = (stars[i].maxrad * (100 - scale) / 100);
-					int radsq = radius * radius;
-					//unsigned char color = GetColor565 (value>>1,value,value>>1);
-					unsigned char color = stars[i].color;
-					for (int cy = -radius; cy <= radius; cy++) { //Draw a circle around the point, for the mask.
-						int cysq = cy * cy;
-						for (int cx = -radius; cx <= radius; cx++) {
-							int cxsq = cx * cx;
-							int dx = cx + px;
-							int dy = cy + py;
-							if ((cxsq + cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0) {
-								if (maskcolor > maskarray [dy][dx]) {
-									maskarray [dy][dx] = maskcolor;
-									screenarray [dy][dx] = color;
-								}
-							}
-						}
-					}
-					/*
-					for(int cy=-radius; cy<=radius; cy++) //Draw a circle around the point, for the color.
-					{
-					   int cysq = cy*cy;
-					for(int cx=-radius; cx<=radius; cx++)
-					   {
-					       int cxsq = cx*cx;
-					       int dx = cx+px;
-					       int dy = cy+py;
-					       if((cxsq+cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0)
-					       {
-					           if (maskarray [dy][dx] == maskcolor)screenarray [dy][dx] = color;
-					       }
-					   }
-					}
-					*/
-				}
-			}
-		}
-	}
-	engine->ReleaseBitmapSurface(canvas);
-	engine->ReleaseBitmapSurface(maskcanvas);
-	engine->NotifySpriteUpdated(slot);
-	engine->NotifySpriteUpdated(maskslot);
-}
-
-
-int CreateTranslucentOverlay(int id, int spriteId, int alpha, int level, int ox, int oy, int mask = 0, int blendmode = 0) {
-	BITMAP *testspr = engine->GetSpriteGraphic(spriteId);
-	if (testspr) overlay[id].sprite = spriteId;
-	else engine->AbortGame("CreateTranslucentOverlay: Invalid spriteId.");
-	engine->ReleaseBitmapSurface(testspr);
-	overlay[id].level = MAX(0, MIN(level, 4));
-	overlay[id].trans = MAX(0, MIN(alpha, 255));
-	overlay[id].spritemask = mask;
-	overlay[id].x = ox;
-	overlay[id].y = oy;
-	overlay[id].enabled = true;
-	overlay[id].blendtype = blendmode;
-	return 0;
-}
-
-int DeleteTranslucentOverlay(int id) {
-	overlay[id].enabled = false;
-	overlay[id].sprite = 0;
-	overlay[id].x = 0;
-	overlay[id].y = 0;
-	overlay[id].level = 0;
-	overlay[id].trans = 0;
-	return 0;
-}
-
-int MoveTranslucentOverlay(int id, int ox, int oy) {
-	overlay[id].x = ox;
-	overlay[id].y = oy;
-	return 0;
-}
-
-int GetTranslucentOverlayX(int id) {
-	return overlay[id].x;
-}
-
-int GetTranslucentOverlayY(int id) {
-	return overlay[id].y;
-}
-
-int GetTranslucentOverlaySprite(int id) {
-	return overlay[id].sprite;
-}
-
-int GetTranslucentOverlayLevel(int id) {
-	return overlay[id].level;
-}
-
-int GetTranslucentOverlayEnabled(int id) {
-	return overlay[id].enabled;
-}
-
-int GetTranslucentOverlayAlpha(int id) {
-	return overlay[id].trans;
-}
-
-int SetTranslucentOverlayAlpha(int id, int alpha) {
-	if (alpha >= 0 && alpha < 256)
-		overlay[id].trans = alpha;
-	else
-		engine->AbortGame("CreateTranslucentOverlay: Invalid alpha selected.");
-	return 0;
-}
-
-int SetTranslucentOverlayEnabled(int id, int toggle) {
-	if (toggle > 0)
-		overlay[id].enabled = true;
-	else
-		overlay[id].enabled = false;
-	return 0;
-}
-
-void SetCharacterReflected(int id, int refl) {
-	if (refl > 0) Reflection.Characters[id].reflect = 1;
-	else Reflection.Characters[id].reflect = 0;
-}
-
-void SetObjectReflected(int id, int refl) {
-	if (refl > 0)
-		Reflection.Objects[id].reflect = 1;
-	else
-		Reflection.Objects[id].reflect = 0;
-}
-
-int GetCharacterReflected(int id) {
-	return Reflection.Characters[id].reflect;
-}
-
-int GetObjectReflected(int id) {
-	return Reflection.Objects[id].reflect;
-}
-
-void ReplaceCharacterReflectionView(int id, int view) {
-	Reflection.Characters[id].replaceview = view - 1;
-}
-
-void SetObjectReflectionIgnoreScaling(int id, int wb) {
-	if (wb) Reflection.Objects[id].ignorescaling = 1;
-	else    Reflection.Objects[id].ignorescaling = 0;
-}
-
-int DrawReflections(int id, int charobj = 0) {
-	int32 screenw, screenh;
-	int32 bgw, bgh;
-	engine->GetScreenDimensions(&screenw, &screenh, nullptr);
-	BITMAP *bgmask = engine->GetBackgroundScene(1);
-	if (bgmask == nullptr) return 1;
-	//BITMAP *virtsc = engine->GetVirtualScreen();
-	BITMAP *walkbehind = engine->GetRoomMask(MASK_WALKBEHIND);
-	//if (!virtsc) engine->AbortGame ("Can't load virtual screen.");
-	if (!walkbehind) engine->AbortGame("DrawRelfections: Can't load Walkbehind into memory.");
-	engine->GetBitmapDimensions(walkbehind, &bgw, &bgh, nullptr);
-	if (!bgmask) engine->AbortGame("DrawReflections: Can't load reflection mask.");
-	//unsigned char **charbuffer = engine->GetRawBitmapSurface (virtsc);
-	unsigned char **wbarray = engine->GetRawBitmapSurface(walkbehind);
-	unsigned char **maskarray = engine->GetRawBitmapSurface(bgmask);
-	//Initialize stuff
-	BITMAP *charsprite = nullptr;
-	BITMAP *charsprite2 = nullptr;
-	AGSCharacter *currchar = nullptr;
-	AGSObject *currobj;
-	int cox = 0, coy = 0, coz = 0;
-	int scale = 0;
-	//Get character, and their sprite.
-	if (charobj == 0) {
-		currchar = engine->GetCharacter(id);
-		/*int view = 0;
-		if (Reflection.Characters[id].replaceview == 0) view = currchar->view + 1;
-		else view = Reflection.Characters[id].replaceview;
-		*/
-		AGSViewFrame *vf = engine->GetViewFrame(currchar->view + 1, currchar->loop, currchar->frame);
-		charsprite = engine->GetSpriteGraphic(vf->pic);
-		long scaling = currchar->flags & CHF_NOSCALING;
-		if (!scaling)scale = engine->GetAreaScaling(currchar->x, currchar->y);
-		else scale = 100;
-		cox = currchar->x;
-		coy = currchar->y;
-		coz = currchar->z;
-	} else if (charobj == 1) {
-		currobj = engine->GetObject(id);
-
-		charsprite = engine->GetSpriteGraphic(currobj->num);
-		if (Reflection.Objects[id].ignorescaling) scale = 100;
-		else scale = engine->GetAreaScaling(currobj->x, currobj->y);
-		cox = currobj->x;
-		if (currobj->baseline < 0) coy = currobj->y;
-		else coy = currobj->baseline;
-		coz = 0;
-	}
-	bool scaled = false;
-	int32 w, h;
-	engine->GetBitmapDimensions(charsprite, &w, &h, nullptr);
-	if (scale != 100) {
-		unsigned char **orig = engine->GetRawBitmapSurface(charsprite);
-		int h1, h2, w1, w2;
-		double fw2, fh2;
-		h1 = h;
-		w1 = w;
-		fh2 = h1 * ((double)scale / 100.0);
-		fw2 = w1 * ((double)scale / 100.0);
-		h2 = static_cast<int>(fh2);
-		w2 = static_cast<int>(fw2);
-		charsprite2 = engine->CreateBlankBitmap(w2, h2, 8);
-		unsigned char **resized = engine->GetRawBitmapSurface(charsprite2);
-		int x_ratio = (int)((w1 << 16) / w2) + 1;
-		int y_ratio = (int)((h1 << 16) / h2) + 1;
-		int x2, y2 ;
-		for (int i = 0; i < h2; i++) {
-			for (int j = 0; j < w2; j++) {
-				x2 = ((j * x_ratio) >> 16) ;
-				y2 = ((i * y_ratio) >> 16) ;
-				resized [i][j] = orig [y2][x2];
-			}
-		}
-		engine->ReleaseBitmapSurface(charsprite2);
-		scaled = true;
-		w = w2;
-		h = h2;
-	} else {
-		charsprite2 = charsprite;
-	}
-	int transamount = 0;
-	unsigned char **spritearray = engine->GetRawBitmapSurface(charsprite2);
-	unsigned char **charbuffer = engine->GetRawBitmapSurface(rcolormap);
-	unsigned char **alphaarray = engine->GetRawBitmapSurface(ralphamap);
-	int i = h - 1, j = 0;
-	int32 ox = cox;
-	if (charobj == 0) ox = ox - (w / 2);
-	int32 oy = coy + coz - 1;
-	engine->RoomToViewport(&ox, &oy);
-	int yoffset = 0;
-	int translevel = 7;
-	//bool dither = false;
-	//bool dodither = false;
-	int counter = 0;
-	int rowcount = 101 - (int)(50.0 * ((double)(scale) / 100.0));
-	int delay = screenh / rowcount;
-	int *obst;
-	int flipped = 0;
-	if (charobj == 0) {
-		int (*sfGetGameParameter)(int, int, int, int);
-		sfGetGameParameter = ((int(*)(int, int, int, int)) engine->GetScriptFunctionAddress("GetGameParameter"));
-		flipped = sfGetGameParameter(13, currchar->view + 1, currchar->loop, currchar->frame);
-	} else flipped = 0;
-	obst = new int [w];
-	for (int k = 0; k < w; k++) {
-		obst[k] = 0;
-	}
-	while (i > 0) {
-		//if ((counter == delay/2-1 || counter == delay-1) && yoffset < 36) dodither = (!dodither);
-		if (counter == delay) {
-			counter = 0;
-			if (translevel > 0) translevel--;
-		} else counter++;
-		yoffset++;
-		while (j < w) {
-			int xoffset;
-			if (flipped == 1) xoffset = w - j - 1;
-			else xoffset = j;
-			int32 rx = ox + xoffset, ry = oy + yoffset;
-			int wbb = 0;
-			engine->ViewportToRoom(&rx, &ry);
-			if (ry > 0 && ry < bgh && rx > 0 && rx < bgw) {
-				if (wbarray [ry][rx] > 0) {
-					wbb = engine->GetWalkbehindBaseline(wbarray[ry][rx]);
-				}
-				if (maskarray[ry][rx] == 21) obst[j] = 1;
-			}
-
-			//dither = (!dither);
-			transamount = 32 * translevel;
-			if (spritearray [i][j] != 0 && oy + yoffset < screenh && ox + xoffset < screenw && oy + yoffset >= 0 && ox + xoffset >= 0) { // If the sprite isn't transparent, and isn't drawn off the edge of the bg.
-				if (wbb < ry && obst[j] == 0 && (oy > reflectionmap[(ox + xoffset) + (screenw * (oy + yoffset))])) {
-					//charbuffer[oy+yoffset][ox+xoffset] = MixColorAlpha (spritearray [i][j],charbuffer[oy+yoffset][ox+xoffset],transamount);
-					charbuffer [oy + yoffset][ox + xoffset] = spritearray [i][j];
-					alphaarray [oy + yoffset][ox + xoffset] = transamount;
-					reflectionmap[(ox + xoffset) + (screenw * (oy + yoffset))] = oy;
-				}
-			}
-			j++;
-		}
-		//if (w % 2 == 0) dither = (!dither);
-		i--;
-		j = 0;
-	}
-
-	delete [] obst;
-	if (scaled == true)engine->FreeBitmap(charsprite2);
-	engine->ReleaseBitmapSurface(charsprite);
-	//engine->ReleaseBitmapSurface (virtsc);
-	//engine->ReleaseBitmapSurface (clutspr);
-	engine->ReleaseBitmapSurface(bgmask);
-	engine->ReleaseBitmapSurface(walkbehind);
-	engine->ReleaseBitmapSurface(rcolormap);
-	engine->ReleaseBitmapSurface(ralphamap);
-	engine->MarkRegionDirty(ox, oy, ox + w, oy + h);
-	return 0;
-}
-
-
-int DrawTransSprite(int spriteId, int bg, int translevel, int mask = 0, int blendmode = 0, int use_objpal = 0) {
-	BITMAP *maskspr = nullptr;
-	unsigned char **maskarray = nullptr;
-	if (mask > 0) maskspr = engine->GetSpriteGraphic(mask);
-	if (!maskspr && mask > 0) {
-		char maskerr [100];
-		snprintf(maskerr, 100, "DrawTransSprite: Can't load mask from slot %d.", mask);
-		engine->AbortGame(maskerr);
-	}
-	// Get a reference to the screen we'll draw onto
-	BITMAP *bgspr = engine->GetSpriteGraphic(bg);
-	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
-	BITMAP *spritespr = engine->GetSpriteGraphic(spriteId);
-	if (!bgspr) engine->AbortGame("DrawTransSprite: Can't load background");
-	//if (!clutspr) engine->AbortGame ("Can't load CLUT spriteId into memory.");
-	if (!spritespr) engine->AbortGame("DrawTransSprite: Can't load overlay spriteId into memory.");
-	// Get its surface
-	int32 sprw, sprh, coldepth;
-	int32 bgw, bgh;
-	engine->GetBitmapDimensions(bgspr, &bgw, &bgh, &coldepth);
-	engine->GetBitmapDimensions(spritespr, &sprw, &sprh, &coldepth);
-
-	unsigned char **bgarray = engine->GetRawBitmapSurface(bgspr);
-	//unsigned char **clutarray = engine->GetRawBitmapSurface (clutspr);
-	unsigned char **spritearray = engine->GetRawBitmapSurface(spritespr);
-	if (mask > 0) maskarray = engine->GetRawBitmapSurface(maskspr);
-	int tloffset = 255 - translevel;
-	int x = 0;
-	int y = 0;
-	//int transamount = 256 * translevel; //old
-	while (y < sprh) {
-		while (x < sprw) {
-			if (spritearray [y][x] != 0 && y < bgh && x < bgw && y >= 0 && x >= 0) { // If the spriteId isn't transparent, and isn't drawn off the edge of the bg.
-				if (mask > 0) {
-					translevel = MAX(maskarray [y][x] - tloffset, 0);
-				}
-				//spritearray[y][x] = cycle_remap[clutarray [cycle_remap[bgarray[y][x]]+transamount][cycle_remap[spritearray [y][x]]]]; //old
-				if (blendmode == 0) spritearray[y][x] = Mix::MixColorAlpha(spritearray [y][x], bgarray[y][x], translevel, use_objpal);
-				else if (blendmode == 1) spritearray[y][x] = Mix::MixColorAdditive(spritearray [y][x], bgarray[y][x], translevel, use_objpal);
-			}
-			x++;
-		}
-		x = 0;
-		y++;
-	}
-
-	// Release the screen so that the engine can continue
-	engine->ReleaseBitmapSurface(bgspr);
-	//engine->ReleaseBitmapSurface (clutspr);
-	engine->ReleaseBitmapSurface(spritespr);
-	engine->NotifySpriteUpdated(spriteId);
-	return 0;
-}
-
-int DrawTranslucentOverlay(int spriteId, int translevel, int ox, int oy, int mask = 0, int blendmode = 0) {
-	if (translevel == 0) return 0;
-	BITMAP *maskspr = nullptr;
-	unsigned char **maskarray = nullptr;
-	// Get a reference to the screen we'll draw onto
-	BITMAP *virtsc = engine->GetVirtualScreen();
-	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
-	BITMAP *spritespr = engine->GetSpriteGraphic(spriteId);
-	if (mask > 0) maskspr = engine->GetSpriteGraphic(mask);
-	if (!virtsc) engine->AbortGame("DrawTranslucentOverlay: Can't load virtual screen.");
-	//if (!clutspr) engine->AbortGame ("Can't load CLUT spriteId into memory.");
-	if (!spritespr) engine->AbortGame("DrawTranslucentOverlay: Can't load overlay spriteId into memory.");
-	// Get its surface
-	int32 sprw, sprh, coldepth;
-	int32 screenw, screenh;
-	engine->GetScreenDimensions(&screenw, &screenh, &coldepth);
-	engine->GetBitmapDimensions(spritespr, &sprw, &sprh, &coldepth);
-	unsigned char **charbuffer = engine->GetRawBitmapSurface(virtsc);
-	unsigned char **spritearray = engine->GetRawBitmapSurface(spritespr);
-	if (mask > 0) {
-		if (!maskspr && mask > 0) {
-			char maskerr [100];
-			snprintf(maskerr, 100, "DrawTransSprite: Can't load mask from slot %d.", mask);
-			engine->AbortGame(maskerr);
-		}
-		maskarray = engine->GetRawBitmapSurface(maskspr);
-	}
-	int tloffset = 255 - translevel;
-	int x = 0;
-	int y = 0;
-	//int transamount = 256 * translevel; //old
-	while (y < sprh) {
-		while (x < sprw) {
-			if (spritearray [y][x] != 0 && y + oy < screenh && x + ox < screenw && y + oy >= 0 && x + ox >= 0) { // If the spriteId isn't transparent, and isn't drawn off the edge of the screen.
-				//charbuffer[y+oy][x+ox] = cycle_remap[clutarray [cycle_remap[charbuffer[y+oy][x+ox]]+transamount][cycle_remap[spritearray [y][x]]]]; //old
-				if (mask > 0) {
-					translevel = MAX(maskarray [y][x] - tloffset, 0);
-				}
-				if (blendmode == 0) {
-					if (translevel == 255) {
-						charbuffer[y + oy][x + ox] = spritearray [y][x];
-					} else charbuffer[y + oy][x + ox] = Mix::MixColorAlpha(spritearray [y][x], charbuffer[y + oy][x + ox], translevel);
-				} else if (blendmode == 1) charbuffer[y + oy][x + ox] = Mix::MixColorAdditive(spritearray [y][x], charbuffer[y + oy][x + ox], translevel);
-			}
-			x++;
-		}
-		x = 0;
-		y++;
-	}
-
-	// Release the screen so that the engine can continue
-	long dirtywidth = ox + sprw;
-	if (dirtywidth > screenw) dirtywidth = screenw - 1;
-	long dirtyheight = oy + sprh;
-	if (dirtyheight > screenh) dirtywidth = screenh - 1;
-	engine->ReleaseBitmapSurface(virtsc);
-	//engine->ReleaseBitmapSurface (clutspr);
-	engine->ReleaseBitmapSurface(spritespr);
-	if (mask > 0) engine->ReleaseBitmapSurface(maskspr);
-	engine->MarkRegionDirty(ox, oy, dirtywidth, dirtyheight);
-
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-
-AGSPalRender::AGSPalRender() : PluginBase() {
-	DLL_METHOD(AGS_GetPluginName);
-	DLL_METHOD(AGS_EngineStartup);
-	DLL_METHOD(AGS_EngineShutdown);
-	DLL_METHOD(AGS_EngineOnEvent);
-}
-
-const char *AGSPalRender::AGS_GetPluginName() {
-	return "PALgorithms Translucent Overlay Renderer";
-}
-
-void AGSPalRender::AGS_EngineStartup(IAGSEngine *lpEngine) {
-	engine = lpEngine;
-
-	// Make sure it's got the version with the features we need
-	if (engine->version < 3) {
-		engine->AbortGame("Engine interface is too old, need newer version of AGS.");
-	}
-	engine->RegisterScriptFunction("PALInternal::LoadCLUT^1", (void *)LoadCLUT);
-	engine->RegisterScriptFunction("PALInternal::CycleRemap^2", (void *)CycleRemap);
-	engine->RegisterScriptFunction("PALInternal::GetColor565^3", (void *)GetColor565);
-	engine->RegisterScriptFunction("PALInternal::GetLuminosityFromPalette^1", (void *)GetLuminosityFromPalette);
-	engine->RegisterScriptFunction("PALInternal::FastSin^1", (void *)AGSFastSin);
-	engine->RegisterScriptFunction("PALInternal::FastCos^1", (void *)AGSFastCos);
-	engine->RegisterScriptFunction("PALInternal::FastRoot^1", (void *)root);
-	engine->RegisterScriptFunction("PALInternal::GetRemappedSlot^1", (void *)GetRemappedSlot);
-	engine->RegisterScriptFunction("PALInternal::ResetRemapping^0", (void *)ResetRemapping);
-	engine->RegisterScriptFunction("PALInternal::GetModifiedBackgroundImage", (void *)GetModifiedBackgroundImage);
-	engine->RegisterScriptFunction("PALInternal::WriteObjectivePalette^4", (void *)WriteObjectivePalette);
-	engine->RegisterScriptFunction("PALInternal::ReadObjectivePaletteR^1", (void *)ReadObjectivePaletteR);
-	engine->RegisterScriptFunction("PALInternal::ReadObjectivePaletteB^1", (void *)ReadObjectivePaletteB);
-	engine->RegisterScriptFunction("PALInternal::ReadObjectivePaletteG^1", (void *)ReadObjectivePaletteG);
-
-	engine->RegisterScriptFunction("Raycast::Render^1", (void *)Raycast_Render);
-	engine->RegisterScriptFunction("Raycast::LoadMap^4", (void *)LoadMap);
-	engine->RegisterScriptFunction("Raycast::Initialize", (void *)Init_Raycaster);
-	engine->RegisterScriptFunction("Raycast::MakeTextures^1", (void *)MakeTextures);
-	engine->RegisterScriptFunction("Raycast::MoveForward^0", (void *)MoveForward);
-	engine->RegisterScriptFunction("Raycast::MoveBackward^0", (void *)MoveBackward);
-	engine->RegisterScriptFunction("Raycast::RotateLeft^0", (void *)RotateLeft);
-	engine->RegisterScriptFunction("Raycast::RotateRight^0", (void *)RotateRight);
-	engine->RegisterScriptFunction("Raycast::SetCameraPosition^2", (void *)Ray_SetPlayerPosition);
-	engine->RegisterScriptFunction("Raycast::GetCameraX^0", (void *)Ray_GetPlayerX);
-	engine->RegisterScriptFunction("Raycast::GetCameraY^0", (void *)Ray_GetPlayerY);
-	engine->RegisterScriptFunction("Raycast::GetCameraAngle^0", (void *)Ray_GetPlayerAngle);
-	engine->RegisterScriptFunction("Raycast::SetCameraAngle^1", (void *)Ray_SetPlayerAngle);
-	engine->RegisterScriptFunction("Raycast::InitSprite^9", (void *)Ray_InitSprite);
-	engine->RegisterScriptFunction("Raycast::UnloadEngine^0", (void *)QuitCleanup);
-	engine->RegisterScriptFunction("Raycast::GetHotspotAtXY^2", (void *)Ray_GetHotspotAt);
-	engine->RegisterScriptFunction("Raycast::GetObjectAtXY^2", (void *)Ray_GetObjectAt);
-	engine->RegisterScriptFunction("Raycast::SetSpriteInteractObj^2", (void *)Ray_SetSpriteInteractObj);
-	engine->RegisterScriptFunction("Raycast::GetSpriteInteractObj^1", (void *)Ray_GetSpriteInteractObj);
-	engine->RegisterScriptFunction("Raycast::SetSpritePosition^3", (void *)Ray_SetSpritePosition);
-	engine->RegisterScriptFunction("Raycast::SetSpriteVertOffset^2", (void *)Ray_SetSpriteVertOffset);
-	engine->RegisterScriptFunction("Raycast::GetSpriteVertOffset^1", (void *)Ray_GetSpriteVertOffset);
-	engine->RegisterScriptFunction("Raycast::GetSpriteX^1", (void *)Ray_GetSpriteX);
-	engine->RegisterScriptFunction("Raycast::GetSpriteY^1", (void *)Ray_GetSpriteY);
-	engine->RegisterScriptFunction("Raycast::SetWallHotspot^2", (void *)Ray_SetWallHotspot);
-	engine->RegisterScriptFunction("Raycast::SetWallTextures^5", (void *)Ray_SetWallTextures);
-	engine->RegisterScriptFunction("Raycast::SetWallSolid^5", (void *)Ray_SetWallSolid);
-	engine->RegisterScriptFunction("Raycast::SetWallIgnoreLighting^5", (void *)Ray_SetWallIgnoreLighting);
-	engine->RegisterScriptFunction("Raycast::SetWallAlpha^5", (void *)Ray_SetWallAlpha);
-	engine->RegisterScriptFunction("Raycast::SetWallBlendType^5", (void *)Ray_SetWallBlendType);
-	engine->RegisterScriptFunction("Raycast::GetMoveSpeed^0", (void *)Ray_GetMoveSpeed);
-	engine->RegisterScriptFunction("Raycast::SetMoveSpeed^1", (void *)Ray_SetMoveSpeed);
-	engine->RegisterScriptFunction("Raycast::GetRotSpeed^0", (void *)Ray_GetRotSpeed);
-	engine->RegisterScriptFunction("Raycast::SetRotSpeed^1", (void *)Ray_SetRotSpeed);
-	engine->RegisterScriptFunction("Raycast::GetWallAt^2", (void *)Ray_GetWallAt);
-	engine->RegisterScriptFunction("Raycast::GetLightAt^2", (void *)Ray_GetLightAt);
-	engine->RegisterScriptFunction("Raycast::SetLightAt^3", (void *)Ray_SetLightAt);
-	engine->RegisterScriptFunction("Raycast::SetWallAt^3", (void *)Ray_SetWallAt);
-	engine->RegisterScriptFunction("Raycast::SetPlaneY^1", (void *)Ray_SetPlaneY);
-	engine->RegisterScriptFunction("Raycast::GetDistanceAt^2", (void *)Ray_GetDistanceAt);
-	engine->RegisterScriptFunction("Raycast::GetSpriteAngle^1", (void *)Ray_GetSpriteAngle);
-	engine->RegisterScriptFunction("Raycast::SetSpriteAngle^2", (void *)Ray_SetSpriteAngle);
-	engine->RegisterScriptFunction("Raycast::SetSpriteView^2", (void *)Ray_SetSpriteView);
-	engine->RegisterScriptFunction("Raycast::GetSpriteView^1", (void *)Ray_GetSpriteView);
-	engine->RegisterScriptFunction("Raycast::SetSpriteFrame^2", (void *)Ray_SetSpriteFrame);
-	engine->RegisterScriptFunction("Raycast::GetSpriteFrame^1", (void *)Ray_GetSpriteFrame);
-	engine->RegisterScriptFunction("Raycast::SetSpritePic^2", (void *)Ray_SetSpritePic);
-	engine->RegisterScriptFunction("Raycast::GetSpritePic^1", (void *)Ray_GetSpritePic);
-	engine->RegisterScriptFunction("Raycast::SetSkyBox^1", (void *)Ray_SetSkyBox);
-	engine->RegisterScriptFunction("Raycast::SetSpriteAlpha^2", (void *)Ray_SetSpriteAlpha);
-	engine->RegisterScriptFunction("Raycast::GetSpriteAlpha^1", (void *)Ray_GetSpriteAlpha);
-	engine->RegisterScriptFunction("Raycast::GetSkyBox^1", (void *)Ray_GetSkyBox);
-	engine->RegisterScriptFunction("Raycast::SetAmbientLight^1", (void *)Ray_SetAmbientLight);
-	engine->RegisterScriptFunction("Raycast::SetAmbientColor^2", (void *)Ray_SetAmbientColor);
-	engine->RegisterScriptFunction("Raycast::GetAmbientLight^0", (void *)Ray_GetAmbientLight);
-	engine->RegisterScriptFunction("Raycast::GetAmbientWeight^0", (void *)Ray_GetAmbientWeight);
-	engine->RegisterScriptFunction("Raycast::GetTileX_At^2", (void *)Ray_GetTileX_At);
-	engine->RegisterScriptFunction("Raycast::GetTileY_At^2", (void *)Ray_GetTileY_At);
-	engine->RegisterScriptFunction("Raycast::DrawTile^2", (void *)Ray_DrawTile);
-	engine->RegisterScriptFunction("Raycast::DrawOntoTile^2", (void *)Ray_DrawOntoTile);
-	engine->RegisterScriptFunction("Raycast::SetNoClip^1", (void *)Ray_SetNoClip);
-	engine->RegisterScriptFunction("Raycast::GetNoClip^0", (void *)Ray_GetNoClip);
-	engine->RegisterScriptFunction("Raycast::GetSpriteScaleX^1", (void *)Ray_GetSpriteScaleX);
-	engine->RegisterScriptFunction("Raycast::SetSpriteScaleX^2", (void *)Ray_SetSpriteScaleX);
-	engine->RegisterScriptFunction("Raycast::GetSpriteScaleY^1", (void *)Ray_GetSpriteScaleY);
-	engine->RegisterScriptFunction("Raycast::SetSpriteScaleY^2", (void *)Ray_SetSpriteScaleY);
-	engine->RegisterScriptFunction("Raycast::GetSpriteBlendType^1", (void *)Ray_GetSpriteBlendType);
-	engine->RegisterScriptFunction("Raycast::SetSpriteBlendType^2", (void *)Ray_SetSpriteBlendType);
-
-
-	engine->RegisterScriptFunction("Raycast::SetFloorAt^3", (void *)Ray_SetFloorAt);
-	engine->RegisterScriptFunction("Raycast::SetCeilingAt^3", (void *)Ray_SetCeilingAt);
-	engine->RegisterScriptFunction("Raycast::GetCeilingAt^2", (void *)Ray_GetCeilingAt);
-	engine->RegisterScriptFunction("Raycast::GetFloorAt^2", (void *)Ray_GetFloorAt);
-	engine->RegisterScriptFunction("Raycast::GetLightingAt^2", (void *)Ray_GetLightingAt);
-	engine->RegisterScriptFunction("Raycast::SetLightingAt^3", (void *)Ray_SetLightingAt);
-	engine->RegisterScriptFunction("Raycast::GetWallHotspot^1", (void *)Ray_GetWallHotspot);
-	engine->RegisterScriptFunction("Raycast::GetWallTexture^2", (void *)Ray_GetWallTexture);
-	engine->RegisterScriptFunction("Raycast::GetWallSolid^2", (void *)Ray_GetWallSolid);
-	engine->RegisterScriptFunction("Raycast::GetWallIgnoreLighting^2", (void *)Ray_GetWallIgnoreLighting);
-	engine->RegisterScriptFunction("Raycast::GetWallAlpha^2", (void *)Ray_GetWallAlpha);
-	engine->RegisterScriptFunction("Raycast::GetWallBlendType^2", (void *)Ray_GetWallBlendType);
-	engine->RegisterScriptFunction("Raycast::SelectTile^3", (void *)Ray_SelectTile);
-	engine->RegisterScriptFunction("Raycast::HasSeenTile^2", (void *)Ray_HasSeenTile);
-
-	engine->RegisterScriptFunction("LensDistort::SetPos^2", (void *)SetLensPos);
-	engine->RegisterScriptFunction("LensDistort::GetX^0", (void *)GetLensX);
-	engine->RegisterScriptFunction("LensDistort::GetY^0", (void *)GetLensY);
-	engine->RegisterScriptFunction("LensDistort::Set^1", (void *)SetLensDrawn);
-	engine->RegisterScriptFunction("LensDistort::IsDrawn^0", (void *)GetLensDrawn);
-	engine->RegisterScriptFunction("LensDistort::SetOffsetClamp^1", (void *)SetLensOffsetClamp);
-	engine->RegisterScriptFunction("LensDistort::GetOffsetClamp^0", (void *)GetLensOffsetClamp);
-	engine->RegisterScriptFunction("LensDistort::GetLevel^0", (void *)GetLensLevel);
-	engine->RegisterScriptFunction("LensDistort::SetLevel^1", (void *)GetLensLevel);
-	engine->RegisterScriptFunction("LensDistort::Initialize^6", (void *)LensInitialize);
-
-	engine->RegisterScriptFunction("Translucence::CreateOverlay^8", (void *)CreateTranslucentOverlay);
-	engine->RegisterScriptFunction("Translucence::DeleteOverlay^1", (void *)DeleteTranslucentOverlay);
-	engine->RegisterScriptFunction("Translucence::Move^3", (void *)MoveTranslucentOverlay);
-	engine->RegisterScriptFunction("Translucence::GetOverlayX^1", (void *)GetTranslucentOverlayX);
-	engine->RegisterScriptFunction("Translucence::GetOverlayY^1", (void *)GetTranslucentOverlayY);
-	engine->RegisterScriptFunction("Translucence::GetOverlaySprite^1", (void *)GetTranslucentOverlaySprite);
-	engine->RegisterScriptFunction("Translucence::GetOverlayLevel^1", (void *)GetTranslucentOverlayLevel);
-	engine->RegisterScriptFunction("Translucence::GetOverlayEnabled^1", (void *)GetTranslucentOverlayEnabled);
-	engine->RegisterScriptFunction("Translucence::GetOverlayAlpha^1", (void *)GetTranslucentOverlayAlpha);
-	engine->RegisterScriptFunction("Translucence::SetOverlayAlpha^2", (void *)SetTranslucentOverlayAlpha);
-	engine->RegisterScriptFunction("Translucence::SetOverlayEnabled^2", (void *)SetTranslucentOverlayEnabled);
-	engine->RegisterScriptFunction("Translucence::DrawTransSprite^6", (void *)DrawTransSprite);
-
-	engine->RegisterScriptFunction("Starfield::GetOverscan^0", (void *)GetStarfieldOverscan);
-	engine->RegisterScriptFunction("Starfield::SetOverscan^1", (void *)SetStarfieldOverscan);
-	engine->RegisterScriptFunction("Starfield::GetOriginX^0", (void *)GetStarfieldOriginX);
-	engine->RegisterScriptFunction("Starfield::GetOriginY^0", (void *)GetStarfieldOriginY);
-	engine->RegisterScriptFunction("Starfield::SetDepthMultiplier^1", (void *)SetStarfieldDepthMultiplier);
-	engine->RegisterScriptFunction("Starfield::GetDepthMultiplier^0", (void *)GetStarfieldDepthMultiplier);
-	engine->RegisterScriptFunction("Starfield::GetMaxStars^0", (void *)GetStarfieldMaxStars);
-	engine->RegisterScriptFunction("Starfield::SetStarSpriteScaleBoost^1", (void *)SetStarSpriteScaleBoost);
-	engine->RegisterScriptFunction("Starfield::GetStarSpriteScaleBoost^0", (void *)GetStarSpriteScaleBoost);
-	engine->RegisterScriptFunction("Starfield::SetStarMaxRadius^2", (void *)SetStarMaxRadius);
-	engine->RegisterScriptFunction("Starfield::GetStarMaxRadius^0", (void *)GetStarMaxRadius);
-	engine->RegisterScriptFunction("Starfield::GetStarX^1", (void *)GetStarX);
-	engine->RegisterScriptFunction("Starfield::GetStarY^1", (void *)GetStarY);
-	engine->RegisterScriptFunction("Starfield::GetStarZ^1", (void *)GetStarZ);
-	engine->RegisterScriptFunction("Starfield::SetStarPosition^4", (void *)SetStarPosition);
-	engine->RegisterScriptFunction("Starfield::RotateStar^4", (void *)RotateStar);
-	engine->RegisterScriptFunction("Starfield::SetStarColor^2", (void *)SetStarColor);
-	engine->RegisterScriptFunction("Starfield::GetStarColor^1", (void *)GetStarColor);
-	engine->RegisterScriptFunction("Starfield::SetStarSprite^2", (void *)SetStarSprite);
-	engine->RegisterScriptFunction("Starfield::GetStarSprite^1", (void *)GetStarSprite);
-	engine->RegisterScriptFunction("Starfield::SetStarSpriteRange^3", (void *)SetStarSpriteRange);
-	engine->RegisterScriptFunction("Starfield::Initialize^2", (void *)InitializeStars);
-	engine->RegisterScriptFunction("Starfield::Iterate^1", (void *)IterateStars);
-	engine->RegisterScriptFunction("Starfield::Draw^2", (void *)DrawStars);
-	engine->RegisterScriptFunction("Starfield::SetOriginPoint^2", (void *)SetStarsOriginPoint);
-
-	engine->RegisterScriptFunction("Plasma::DoFire^8", (void *)DoFire);
-	engine->RegisterScriptFunction("Plasma::SetPlasmaType^5", (void *)SetPlasmaType);
-	engine->RegisterScriptFunction("Plasma::ResetPlasmaSettings^0", (void *)ResetPlasmaSettings);
-	engine->RegisterScriptFunction("Plasma::DrawPlasma^3", (void *)DrawPlasma);
-	engine->RegisterScriptFunction("Plasma::SetRootType^1", (void *)SetPlasmaRootType);
-	engine->RegisterScriptFunction("Plasma::GetRootType^0", (void *)GetPlasmaRootType);
-
-	engine->RegisterScriptFunction("Reflections::Set^1", (void *)SetReflections);
-	engine->RegisterScriptFunction("Reflections::IsReflecting^0", (void *)IsReflectionsOn);
-	engine->RegisterScriptFunction("Reflections::SetCharacterReflected^2", (void *)SetCharacterReflected);
-	engine->RegisterScriptFunction("Reflections::GetCharacterReflected^1", (void *)GetCharacterReflected);
-	engine->RegisterScriptFunction("Reflections::SetObjectReflected^2", (void *)SetObjectReflected);
-	engine->RegisterScriptFunction("Reflections::GetObjectReflected^1", (void *)GetObjectReflected);
-	engine->RegisterScriptFunction("Reflections::ReplaceCharacterReflectionView^2", (void *)ReplaceCharacterReflectionView);
-	engine->RegisterScriptFunction("Reflections::SetObjectReflectionIgnoreScaling^2", (void *)SetObjectReflectionIgnoreScaling);
-	engine->RequestEventHook(AGSE_PRESCREENDRAW);
-	engine->RequestEventHook(AGSE_PREGUIDRAW);
-	engine->RequestEventHook(AGSE_POSTSCREENDRAW);
-	engine->RequestEventHook(AGSE_SAVEGAME);
-	engine->RequestEventHook(AGSE_RESTOREGAME);
-	engine->RequestEventHook(AGSE_ENTERROOM);
-	stars = new starstype [MAX_STARS];
-	Starfield.maxstars = MAX_STARS;
-	Starfield.depthmultiplier = 256;
-	Starfield.speed = 0.5;
-	Starfield.originx = 160;
-	Starfield.originy = 100;
-	Reflection.Characters = new charrefopt [engine->GetNumCharacters()]();
-	lens = new LensDistort [LENS_WIDTH * LENS_WIDTH]();
-	//PreMultiply_Alphas ();
-	plasmaroottype = 0;
-	Make_Sin_Lut();
-	Init_Raycaster();
-}
-
-void AGSPalRender::AGS_EngineShutdown() {
-	// no work to do here - but if we had created any dynamic sprites,
-	// we should delete them here
-	delete[] Reflection.Characters;
-	delete[] Reflection.Objects;
-	//QuitCleanup();
-}
-
-int64 AGSPalRender::AGS_EngineOnEvent(int event, NumberPtr data) {
-	if (event == AGSE_PRESCREENDRAW && clutslot > 0) {
-		if (drawreflections) {
-			int32 sh, sw = 0;
-			engine->GetScreenDimensions(&sw, &sh, nullptr);
-			reflectionmap = new long[sw * sh]();
-			rcolormap = engine->CreateBlankBitmap(sw, sh, 8);
-			ralphamap = engine->CreateBlankBitmap(sw, sh, 8);
-			for (int i = 0; i < engine->GetNumCharacters(); i++) {
-				if (Reflection.Characters[i].reflect == 0) continue;
-				AGSCharacter *tempchar = engine->GetCharacter(i);
-				if (tempchar->room != engine->GetCurrentRoom()) continue;  //if character isn't even in the room, go to next iteration.
-				int32 vx = tempchar->x;
-				int32 vy = tempchar->y;
-				engine->RoomToViewport(&vx, &vy);
-				AGSViewFrame *vf = engine->GetViewFrame(tempchar->view + 1, tempchar->loop, tempchar->frame);
-				int w = engine->GetSpriteWidth(vf->pic);
-				int h = engine->GetSpriteHeight(vf->pic);
-				vx = vx - (w / 2);
-				int32 vxmax = vx + w;
-				int32 vymax = vy + h;
-				if (vxmax < 0 || vy > sh || vx > sw || vymax < 0) continue; //if all of the sprite is off screen in any direction, go to next iteration
-				DrawReflections(i, 0);
-			}
-			for (int i = 0; i < engine->GetNumObjects(); i++) {
-				if (Reflection.Objects[i].reflect == 0) continue;
-				AGSObject *tempobj = engine->GetObject(i);
-				if (!tempobj->on) continue;
-				int32 vx = tempobj->x;
-				int32 vy = tempobj->baseline - tempobj->y;
-				engine->RoomToViewport(&vx, &vy);
-				int32 w = engine->GetSpriteWidth(tempobj->num);
-				int32 h = engine->GetSpriteHeight(tempobj->num);
-				int32 vxmax = vx + w;
-				int32 vymax = vy + h;
-				if (vxmax < 0 || vy > sh || vx > sw || vymax < 0) continue; //if all of the sprite is off screen in any direction, go to next iteration
-				DrawReflections(i, 1);
-			}
-			BITMAP *virtsc = engine->GetVirtualScreen();
-			unsigned char **screenbuffer = engine->GetRawBitmapSurface(virtsc);
-			unsigned char **colorbuffer = engine->GetRawBitmapSurface(rcolormap);
-			unsigned char **alphabuffer = engine->GetRawBitmapSurface(ralphamap);
-			for (int y = 0; y < sh; y++)
-				for (int x = 0; x < sw; x++)
-					screenbuffer[y][x] = Mix::MixColorAlpha(colorbuffer[y][x], screenbuffer[y][x], alphabuffer[y][x]);
-			engine->ReleaseBitmapSurface(rcolormap);
-			engine->ReleaseBitmapSurface(ralphamap);
-			engine->ReleaseBitmapSurface(virtsc);
-			engine->FreeBitmap(rcolormap);
-			engine->FreeBitmap(ralphamap);
-			delete [] reflectionmap;
-		}
-		int i = 0;
-		if (LensOption.draw == 1 && LensOption.level == 0) DrawLens(LensOption.x, LensOption.y);
-		while (i < MAX_OVERLAYS) {
-			if (overlay[i].enabled && overlay[i].level == 0) {
-				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
-			}
-			i++;
-		}
-		if (LensOption.draw == 1 && LensOption.level == 1) DrawLens(LensOption.x, LensOption.y);
-	}
-	if (event == AGSE_PREGUIDRAW && clutslot > 0) {
-		int i = 0;
-		if (LensOption.draw == 1 && LensOption.level == 1) DrawLens(LensOption.x, LensOption.y);
-		while (i < MAX_OVERLAYS) {
-			if (overlay[i].enabled && overlay[i].level == 1) {
-				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
-			}
-			i++;
-		}
-		if (LensOption.draw == 1 && LensOption.level == 2) DrawLens(LensOption.x, LensOption.y);
-	}
-	if (event == AGSE_POSTSCREENDRAW && clutslot > 0) {
-		int i = 0;
-		if (LensOption.draw == 1 && LensOption.level == 3) DrawLens(LensOption.x, LensOption.y);
-		while (i < MAX_OVERLAYS) {
-			if (overlay[i].enabled && overlay[i].level == 2) {
-				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
-			}
-			i++;
-		}
-		if (LensOption.draw == 1 && LensOption.level == 4) DrawLens(LensOption.x, LensOption.y);
-	}
-	if (event == AGSE_SAVEGAME) {
-		Serializer s(engine, data, false);
-		syncGame(s);
-	}
-	if (event == AGSE_RESTOREGAME) {
-		Serializer s(engine, data, true);
-		syncGame(s);
-	}
-	if (event == AGSE_ENTERROOM) {
-		ResetRemapping();
-		delete[] Reflection.Objects;
-		Reflection.Objects = new objrefopt [engine->GetNumObjects()]();
-	}
-	return 0;
-}
-
-void AGSPalRender::syncGame(Serializer &s) {
-	for (int i = 0; i < MAX_OVERLAYS; ++i) {
-		s.syncAsInt(overlay[i].sprite);
-		s.syncAsInt(overlay[i].spritemask);
-		s.syncAsInt(overlay[i].x);
-		s.syncAsInt(overlay[i].y);
-		s.syncAsInt(overlay[i].level);
-		s.syncAsInt(overlay[i].trans);
-		s.syncAsInt(overlay[i].blendtype);
-		s.syncAsBool(overlay[i].enabled);
-	}
-	s.syncAsInt(clutslot);
-	s.syncAsInt(drawreflections);
-
-	for (int j = 0; j < 256; ++j)
-		s.syncAsByte(cycle_remap[j]);
-
-	for (int j = 0; j < 256; ++j) {
-		s.syncAsByte(objectivepal[j].r);
-		s.syncAsByte(objectivepal[j].b);
-		s.syncAsByte(objectivepal[j].g);
-	}
-
-	for (int j = 0; j < 256; ++j) {
-		s.syncAsDouble(sprite[j].x);
-		s.syncAsDouble(sprite[j].y);
-		s.syncAsInt(sprite[j].texture);
-		s.syncAsByte(sprite[j].alpha);
-		s.syncAsDouble(sprite[j].uDivW);
-		s.syncAsDouble(sprite[j].uDivH);
-		s.syncAsDouble(sprite[j].vMove);
-		s.syncAsDouble(sprite[j].hMove);
-		s.syncAsInt8(sprite[j].objectinteract);
-		s.syncAsInt(sprite[j].view);
-		s.syncAsInt(sprite[j].frame);
-		s.syncAsInt(sprite[j].angle);
-	}
-
-	for (int j = 0; j < 256; ++j) {
-		for (int k = 0; k < 4; ++k) {
-			s.syncAsInt(wallData[j].texture[k]);
-			s.syncAsInt(wallData[j].solid[k]);
-			s.syncAsInt(wallData[j].ignorelighting[k]);
-			s.syncAsInt(wallData[j].alpha[k]);
-			s.syncAsInt(wallData[j].blendtype[k]);
-			s.syncAsInt(wallData[j].mask[k]);
-		}
-
-		s.syncAsByte(wallData[j].hotspotinteract);
-	}
-
-	s.syncAsBool(raycastOn);
-	s.syncAsBool(heightmapOn);
-	s.syncAsDouble(posX);
-	s.syncAsDouble(posY);
-	s.syncAsDouble(dirX);
-	s.syncAsDouble(dirY);
-	s.syncAsDouble(planeX);
-	s.syncAsDouble(planeY);
-	s.syncAsDouble(moveSpeed);
-	s.syncAsDouble(rotSpeed);
-
-	if (raycastOn) { //If the raycaster is active, we have additional data to save.
-		for (int i = 0; i < MAP_WIDTH; ++i)
-			for (int j = 0; j < MAP_HEIGHT; ++j) {
-				s.syncAsByte(worldMap[i][j]);
-				s.syncAsByte(lightMap[i][j]);
-				s.syncAsInt(ceilingMap[i][j]);
-				s.syncAsInt(floorMap[i][j]);
-				s.syncAsInt(heightMap[i][j]);
-			}
-	}
-
-	s.syncAsInt(textureSlot);
-	if (s.isLoading() && textureSlot)
-		MakeTextures(textureSlot);
-
-	s.syncAsInt(skybox);
-	s.syncAsInt(ambientlight);
-
-	if (s.isLoading())
-		LoadCLUT(clutslot);
-}
-
-} // namespace AGSPalRender
-} // namespace Plugins
-} // namespace AGS3
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ags/lib/allegro.h"
+#include "ags/plugins/ags_pal_render/ags_pal_render.h"
+#include "ags/plugins/ags_pal_render/pal_render.h"
+#include "ags/plugins/ags_pal_render/raycast.h"
+#include "ags/ags.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSPalRender {
+
+#define MAX_OVERLAYS 128
+#define MAX_STARS 1024
+#define MAX_DEPTH 64
+
+#define PI         (3.1415926535f)
+#define HALF_PI    (0.5f * PI)
+#define TWO_PI     (2.0f * PI)
+#define TWO_PI_INV (1.0f / TWO_PI)
+
+const float halfpi = (0.5f * PI);
+const float twopi  = (2.0f * PI);
+const float twopi_inv = (1.0f / TWO_PI);
+const float pisquared = PI * PI;
+const float picubed = PI * PI * PI;
+
+IAGSEngine *engine;
+
+//unsigned char clut[256][256];
+unsigned char clut[65536];
+
+struct transoverlaytype {
+	int sprite;
+	int spritemask;
+	int blendtype;
+	int x;
+	int y;
+	int trans;
+	int level;
+	bool enabled;
+} overlay[MAX_OVERLAYS];
+
+int clutslot;
+int drawreflections;
+byte cycle_remap[256];
+
+struct starstype {
+	float x;
+	float y;
+	float z;
+	unsigned char color;
+	long sprite;
+	int maxrad;
+	int scaleboost;
+};
+starstype *stars;
+
+struct starsoptions {
+	float speed;
+	int maxstars;
+	int depthmultiplier;
+	int originx;
+	int originy;
+	int overscan;
+} Starfield;
+long *reflectionmap;
+BITMAP *rcolormap;
+BITMAP *ralphamap;
+
+struct charrefopt {
+	char reflect;
+	int replaceview;
+};
+
+struct objrefopt {
+	char reflect;
+	char ignorescaling;
+};
+
+struct reflectionopt {
+	charrefopt *Characters;
+	objrefopt *Objects;
+	int blendslot;
+	int blendamount;
+} Reflection;
+
+int dummy;
+
+#define LENS_WIDTH 150
+
+struct LensDistort {
+	int xoffset;
+	int yoffset;
+};
+
+LensDistort *lens;
+struct LensOpt {
+	bool draw;
+	int lenswidth;
+	int lenszoom;
+	int level;
+	int x;
+	int y;
+	int clampoffset;
+} LensOption;
+
+const int alphamultiply [4096] = {
+//#include "alphamultiply.txt"
+};
+float rot_sine_LUT[360];
+float rot_cos_LUT[360];
+
+BITMAP *backgroundimage;
+
+PALSTRUCT objectivepal[256];
+int bgimgspr;
+
+void WriteObjectivePalette(unsigned char index, unsigned char r, unsigned char b, unsigned char g) {
+	objectivepal[index].r = r;
+	objectivepal[index].b = b;
+	objectivepal[index].g = g;
+}
+
+int ReadObjectivePaletteR(unsigned char index) {
+	return objectivepal[index].r;
+}
+
+int ReadObjectivePaletteB(unsigned char index) {
+	return objectivepal[index].b;
+}
+int ReadObjectivePaletteG(unsigned char index) {
+	return objectivepal[index].g;
+}
+
+
+#define SQRT_MAGIC_F 0x5f3759df
+float  q3sqrt(const float x) {
+	const float xhalf = 0.5f * x;
+
+	union { // get bits for floating value
+		float x;
+		int i;
+	} u;
+	u.x = x;
+	u.i = SQRT_MAGIC_F - (u.i >> 1);  // gives initial guess y0
+	return x * u.x * (1.5f - xhalf * u.x * u.x); // Newton step, repeating increases accuracy
+}
+
+void Make_Sin_Lut() {
+	for (int angle = 0; angle < 360; angle++) {
+		double rad = (angle * PI) / 180.0;
+		rot_sine_LUT [angle] = static_cast<float>(sin(rad));
+		rot_cos_LUT [angle]  = static_cast<float>(cos(rad));
+	}
+}
+
+/*
+void PreMultiply_Alphas () //Ha ha, this isn't the kind of premultiplcation you're thinking of.
+{
+    for (int y=0;y<64;y++)
+        for (int x=0;x<64;x++)
+            alphamultiply [y*64+x] = y*x;
+}
+*/
+
+int GetModifiedBackgroundImage() {
+	return bgimgspr;
+}
+
+unsigned short root(unsigned short x) {
+	unsigned short a, b;
+	b = x;
+	a = x = 0x3f;
+	x = b / x;
+	a = x = (x + a) >> 1;
+	x = b / x;
+	a = x = (x + a) >> 1;
+	x = b / x;
+	x = (x + a) >> 1;
+	return (x);
+}
+
+
+float Hill(float x) {
+	const float a0 = 1.0f;
+	const float a2 = 2.0f / PI - 12.0f / (pisquared);
+	const float a3 = 16.0f / (picubed) - 4.0f / (pisquared);
+	const float xx = x * x;
+	const float xxx = xx * x;
+
+	return a0 + a2 * xx + a3 * xxx;
+}
+
+float FastSin(float x) {
+	// wrap x within [0, TWO_PI)
+	const float a = x * twopi_inv;
+	x -= static_cast<int>(a) * twopi;
+	if (x < 0.0f)
+		x += twopi;
+
+	// 4 pieces of hills
+	if (x < halfpi)
+		return Hill(halfpi - x);
+	else if (x < PI)
+		return Hill(x - halfpi);
+	else if (x < 3.0f * halfpi)
+		return -Hill(3.0f * halfpi - x);
+	else
+		return -Hill(x - 3.0f * halfpi);
+}
+
+float FastCos(float x) {
+	return FastSin(x + halfpi);
+}
+
+FLOAT_RETURN_TYPE AGSFastSin(SCRIPT_FLOAT(x)) {
+	INIT_SCRIPT_FLOAT(x);
+	x = FastSin(x);
+	RETURN_FLOAT(x);
+}
+
+FLOAT_RETURN_TYPE AGSFastCos(SCRIPT_FLOAT(x)) {
+	INIT_SCRIPT_FLOAT(x);
+	x = FastSin(x + halfpi);
+	RETURN_FLOAT(x);
+}
+
+
+void DrawLens(int ox, int oy) {
+	int32 sh, sw = 0;
+	engine->GetScreenDimensions(&sw, &sh, nullptr);
+	BITMAP *virtsc = engine->GetVirtualScreen();
+	if (!virtsc) engine->AbortGame("DrawLens: Cannot get virtual screen.");
+	BITMAP *lenswrite = engine->CreateBlankBitmap(LensOption.lenswidth, LensOption.lenswidth, 8);
+	uint8 *vScreen = engine->GetRawBitmapSurface(virtsc);
+	uint8 *lensarray = engine->GetRawBitmapSurface(lenswrite);
+	int virtscPitch = engine->GetBitmapPitch(virtsc);
+	int lenswritePitch = engine->GetBitmapPitch(lenswrite);
+	int radius = LensOption.lenswidth >> 1;
+	for (int y = 0, lensy = 0; y < LensOption.lenswidth; y++, lensy += lenswritePitch) {
+		int ypos = y * LensOption.lenswidth;
+		for (int x = 0; x < LensOption.lenswidth; x++) {
+			int lenspos = ypos + x;
+			int coffx = lens[lenspos].xoffset;
+			int coffy = lens[lenspos].yoffset;
+			if (oy + coffy > 0 && oy + coffy < sh && ox + coffx > 0 && ox + coffx < sw) {
+				lensarray[lensy + x] = vScreen[(oy + coffy) * virtscPitch + ox + coffx];
+				//vScreen[(oy + coffy) * virtscPitch + ox + coffx] = ABS(coffy);
+			}
+		}
+	}
+	/*
+	for (int y=0, lensy = 0;y<LensOption.lenswidth;y++, lensy += lenswritePitch)
+	{
+	    int ypos = y*LensOption.lenswidth;
+	    for (int x=0;x<LensOption.lenswidth;x++)
+	    {
+	        if (oy+y > 0 && oy+y < sh && ox+x > 0 && ox+x < sw)
+	        {
+	            vScreen[(oy+y) * virtscPitch + ox+x] = lensarray[lensy + x];
+	        }
+	    }
+	}
+	*/
+	int radsq = radius * radius;
+	for (int cy = -radius, lensy = 0; cy <= radius; cy++, lensy += lenswritePitch) { //Draw a circle around the point, for the mask.
+		int cysq = cy * cy;
+		for (int cx = -radius; cx <= radius; cx++) {
+			int cxsq = cx * cx;
+			int dx = cx + ox;
+			int dy = cy + oy;
+			if ((cxsq + cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0 && cy + radius < LensOption.lenswidth - 1 && cx + radius < LensOption.lenswidth - 1) {
+				//if (cy+radius < 0 || cx+radius < 0) engine->AbortGame ("I did something wrong");
+				vScreen[dy * virtscPitch + dx] = lensarray[lensy + cx + radius];
+			}
+		}
+	}
+
+	engine->ReleaseBitmapSurface(lenswrite);
+	engine->ReleaseBitmapSurface(virtsc);
+	engine->FreeBitmap(lenswrite);
+}
+
+void SetLensPos(int x, int y) {
+	LensOption.x = x;
+	LensOption.y = y;
+}
+
+int GetLensX() {
+	return LensOption.x;
+}
+
+int GetLensY() {
+	return LensOption.y;
+}
+
+void SetLensDrawn(int toggle) {
+	if (toggle > 0) LensOption.draw = 1;
+	else LensOption.draw = 0;
+}
+
+int GetLensDrawn() {
+	return LensOption.draw;
+}
+
+void SetLensOffsetClamp(int clamp) {
+	if (clamp < 0) LensOption.clampoffset = LensOption.lenswidth;
+	else LensOption.clampoffset = clamp;
+}
+
+int GetLensOffsetClamp() {
+	return LensOption.clampoffset;
+}
+
+int GetLensLevel() {
+	return LensOption.level;
+}
+
+void SetLensLevel(int level) {
+	if (level < 0 || level > 4) engine->AbortGame("SetLensLevel: Invalid level.");
+	else LensOption.level = level;
+}
+
+void LensInitialize(int width, int zoom, int lensx, int lensy, int level, int clamp = -1) {
+	int32 sw, sh, radius;
+	if (width < 1) engine->AbortGame("Invalid lens dimension!");
+	radius = width >> 1;
+	lens = new LensDistort [width * width]();
+	engine->GetScreenDimensions(&sw, &sh, nullptr);
+	int radsq = radius * radius;
+	int zoomsq = zoom * zoom;
+	for (int y = 0; y < radius; y++) {
+		int ysq = y * y;
+		for (int x = 0; x < radius; x++) {
+			int lx, ly;
+			int xsq = x * x;
+			if ((xsq + ysq) < (radsq)) {
+				float shift = zoom / sqrt((float)(zoomsq - (xsq + ysq - radsq)));
+				lx = (int)(x * shift - x);
+				ly = (int)(y * shift - y);
+			} else {
+				lx = 0;
+				ly = 0;
+			}
+			lens[(radius - y)*width + (radius - x)].xoffset =  lx;
+			lens[(radius - y)*width + (radius - x)].yoffset =  ly;
+			lens[(radius + y)*width + (radius + x)].xoffset = -lx;
+			lens[(radius + y)*width + (radius + x)].yoffset = -ly;
+			lens[(radius + y)*width + (radius - x)].xoffset =  lx;
+			lens[(radius + y)*width + (radius - x)].yoffset = -ly;
+			lens[(radius - y)*width + (radius + x)].xoffset = -lx;
+			lens[(radius - y)*width + (radius + x)].yoffset =  ly;
+		}
+	}
+	LensOption.lenswidth = width;
+	LensOption.lenszoom = zoom;
+	if (clamp < 0) LensOption.clampoffset = width;
+	else LensOption.clampoffset = clamp;
+	LensOption.x = lensx;
+	LensOption.y = lensy;
+	if (level < 0 || level > 4) engine->AbortGame("SetLensLevel: Invalid level.");
+	else LensOption.level = level;
+}
+
+void ResetRemapping() {
+	for (int j = 0; j < 256; ++j) {
+		cycle_remap [j] = j;
+	}
+}
+
+#define MAX_PLASMA_COMPLEXITY 4
+int plasmatype[MAX_PLASMA_COMPLEXITY];
+int plasmadata [MAX_PLASMA_COMPLEXITY];
+int plasmadata2 [MAX_PLASMA_COMPLEXITY];
+int plasmadata3 [MAX_PLASMA_COMPLEXITY];
+int plasmaroottype;
+
+
+void SetPlasmaRootType(int real) {
+	if (real) plasmaroottype = 1;
+	else plasmaroottype = 0;
+}
+
+int GetPlasmaRootType() {
+	return plasmaroottype;
+}
+
+void SetPlasmaType(int component, int type, int data, int data2, int data3) {
+	if (component >= MAX_PLASMA_COMPLEXITY) engine->AbortGame("Plasma too complex!");
+	else {
+		plasmatype [component] = type;
+		plasmadata [component] = data;
+		plasmadata2[component] = data2;
+		plasmadata3[component] = data3;
+	}
+
+	//0 = None.
+	//1 = Horizontal Bars (data=width)
+	//2 = Vertical Bars (data=width)
+	//3 = Circle (data=x,data2=y,data3=width)
+	//4 = Diagonal Bars (data=width)
+}
+
+void ResetPlasmaSettings() {
+	int i = 0;
+	while (i < MAX_PLASMA_COMPLEXITY) {
+		plasmatype [i] = 0;
+		plasmadata [i] = 0;
+		plasmadata2[i] = 0;
+		plasmadata3[i] = 0;
+		i++;
+	}
+}
+
+void DrawPlasma(int slot, int palstart, int palend) {
+	BITMAP *plasmaspr = engine->GetSpriteGraphic(slot);
+	if (!plasmaspr) engine->AbortGame("Plasma: Not a sprite I can load.");
+	int32 w, h, basecol, range = 0;
+	if (palend > palstart) {
+		range = palend - palstart;
+		basecol = palstart;
+	} else {
+		range = palstart - palend;
+		basecol = palend;
+	}
+	engine->GetBitmapDimensions(plasmaspr, &w, &h, nullptr);
+	uint8 *plasmarray = engine->GetRawBitmapSurface(plasmaspr);
+	int plasmapitch = engine->GetBitmapPitch(plasmaspr);
+	double frange = range / 2.0;
+	int complex = 0;
+	int color = 0;
+	int i = 0;
+	while (i < MAX_PLASMA_COMPLEXITY) {
+		if (plasmatype[i] > 0) complex++;
+		i++;
+	}
+	for (int x = 0; x < w; x++) {
+		for (int y = 0, plasmay = 0; y < h; y++, plasmay += plasmapitch) {
+			color = 0;
+			for (int p = 0; p < MAX_PLASMA_COMPLEXITY; p++) {
+				if (plasmatype[p] == 1) { //1 = Horizontal Bars (data=width)
+					color += int(frange + (frange * FastSin(y / (float)plasmadata[p])));
+				} else if (plasmatype[p] == 2) { //2 = Vertical Bars (data=width)
+					color += int(frange + (frange * FastSin(x / (float)plasmadata[p])));
+				} else if (plasmatype[p] == 3) { //3 = Circle (data=x,data2=y,data3=width)
+					int cx, cy = 0;
+					cx = plasmadata [p];
+					cy = plasmadata2 [p];
+					if (plasmaroottype == 1) color += int(frange + (frange * FastSin(q3sqrt((float)((x - cx) * (x - cx) + (y - cy) * (y - cy)) / plasmadata3[p]))));
+					else color += int(frange + (frange * FastSin(root(((x - cx) * (x - cx) + (y - cy) * (y - cy)) / plasmadata3[p]))));
+				} else if (plasmatype[p] == 4) { //4 = Diagonal Bars (data=width)
+					color += int(frange + (frange * FastSin((x + y) / (float)plasmadata[p])));
+				}
+			}
+			if (color > 0 && complex > 0) color = color / complex;
+			plasmarray[plasmay + x] = static_cast<unsigned char>(basecol + color);
+		}
+	}
+	engine->ReleaseBitmapSurface(plasmaspr);
+	engine->NotifySpriteUpdated(slot);
+}
+
+void DoFire(int spriteId, int masksprite, int palstart, int palend, int strength, int seed, int cutoff, int windspeed) {
+	BITMAP *firespr = engine->GetSpriteGraphic(masksprite);
+	BITMAP *firecolorspr = engine->GetSpriteGraphic(spriteId);
+	BITMAP *seedspr;
+	int32 w, h = 0;
+	int range, basecol, dir = 0;
+	if (palend > palstart) {
+		range = palend - palstart;
+		basecol = palstart;
+		dir = 1;
+	} else {
+		range = palstart - palend;
+		basecol = palend;
+		dir = -1;
+	}
+	int divider = 256 / range;
+	engine->GetBitmapDimensions(firespr, &w, &h, nullptr);
+	uint8 *fire = engine->GetRawBitmapSurface(firespr);
+	uint8 *color = engine->GetRawBitmapSurface(firecolorspr);
+	int firePitch = engine->GetBitmapPitch(firespr);
+	int colorPitch = engine->GetBitmapPitch(firecolorspr);
+	int sparky = 0;
+	//srand(time(NULL));
+	for (int y = 0, firey = 0; y < h - 1; y++, firey += firePitch) {
+		if ((int)::AGS::g_vm->getRandomNumber(9) > 7 - windspeed) { //Wind right
+			for (int x = w - 1; x > 1; x--) {
+				fire[firey + x] = fire[firey + x - 1];
+			}
+		} else if ((int)::AGS::g_vm->getRandomNumber(9) > 7 + windspeed) { // wind left
+			for (int x = 0; x < w - 1; x++) {
+				fire[firey + x] = fire[firey + x + 1];
+			}
+		}
+	}
+	for (int x = 0; x < w; x++) {
+		sparky = ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % (h - 2));
+		int firexy = (h - sparky) * firePitch + x;
+		if (sparky < h && sparky > 0 && fire[firexy] > cutoff &&
+				ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % 10) > 7)
+			fire[firexy] = 255;
+		sparky = ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % (h - 2));
+		if (sparky < h && sparky > 0 && fire[firexy] > cutoff &&
+				ABS((int)::AGS::g_vm->getRandomNumber(0x7fffffff) % 10) > 7)
+			fire[firexy] = 0;
+	}
+	if (seed == 0) {
+		int firey = (h - 1) * firePitch;
+		for (int x = 0; x < w; x++)
+			fire[firey + x] = 255;
+		firey = (h - 2) * firePitch;
+		for (int x = 0; x < w; x++)
+			fire[firey + x] = ::AGS::g_vm->getRandomNumber(255);
+	} else if (seed > 0) {
+		seedspr = engine->GetSpriteGraphic(seed);
+		BITMAP *virtsc = engine->GetVirtualScreen();
+		engine->SetVirtualScreen(firespr);
+		engine->BlitBitmap(0, 0, seedspr, 1);
+		engine->SetVirtualScreen(virtsc);
+		engine->ReleaseBitmapSurface(virtsc);
+		engine->ReleaseBitmapSurface(seedspr);
+		engine->NotifySpriteUpdated(spriteId);
+		engine->NotifySpriteUpdated(masksprite);
+	}
+
+	for (int y = 0, firey = 0, colory = 0; y < h - 1; y++, firey += firePitch, colory += colorPitch) {
+		for (int x = 0; x < w; x++) {
+			fire[firey + x] =
+			    ((fire[((y + 1) % h) * firePitch + ((x - 1 + w) % w)]
+			      + fire[((y + 1) % h) * firePitch + ((x) % w)]
+			      + fire[((y + 1) % h) * firePitch + ((x + 1) % w)]
+			      + fire[((y + 2) % h) * firePitch + ((x) % w)])
+			     * 100) / (400 + (100 - strength));
+			if (fire[firey + x] < cutoff) fire[firey + x] = 0;
+			//if (fire[firey + x] ==255) color [colory + x] = palend;
+			else color [colory + x] = static_cast<uint8>(basecol + (fire[firey + x] / divider) * dir);
+		}
+	}
+	engine->ReleaseBitmapSurface(firespr);
+	engine->ReleaseBitmapSurface(firecolorspr);
+	engine->NotifySpriteUpdated(spriteId);
+	engine->NotifySpriteUpdated(masksprite);
+}
+
+/*
+unsigned char MixColorAlpha (unsigned char fg,unsigned char bg,unsigned char alpha)
+{
+    //unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
+    //unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
+    //BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
+    //if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
+    //uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
+    AGSColor *palette = engine->GetPalette ();
+    int i=0;
+    int out_r = (palette[fg].r>>1) * alpha + (palette[bg].r>>1) * (255 - alpha);
+    int out_g = palette[fg].g * alpha + palette[bg].g * (255 - alpha);
+    int out_b = (palette[fg].b>>1) * alpha + (palette[bg].b>>1) * (255 - alpha);
+    //unsigned char ralpha = alpha>>2;
+    //unsigned char invralpha = 64-ralpha;
+    //if (ralpha > alpha) engine->AbortGame ("wtf");
+    //int out_r = alphamultiply[(palette[fg].r>>1)][ralpha] + alphamultiply[(palette[bg].r>>1)][(invralpha)];
+    //int out_g = alphamultiply[(palette[fg].g)][ralpha] + alphamultiply[(palette[bg].g)][(invralpha)];
+    //int out_b = alphamultiply[(palette[fg].b>>1)][ralpha] + alphamultiply[(palette[bg].b>>1)][(invralpha)];
+    out_r = (out_r + 1 + (out_r >> 8)) >> 8;
+    out_g = (out_g + 1 + (out_g >> 8)) >> 8;
+    out_b = (out_b + 1 + (out_b >> 8)) >> 8;
+    i = ((out_r << 11) | (out_g << 5) | out_b);
+    unsigned char (*clutp) = clut;
+    //unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
+    unsigned char result = cycle_remap [*(clutp+i)]; //Once again, to make sure that the palette slot used is the right one.
+    //engine->ReleaseBitmapSurface (clutspr);
+    return result;
+}
+
+unsigned char MixColorAdditive (unsigned char fg,unsigned char bg,unsigned char alpha)
+{
+    //unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
+    //unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
+    //BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
+    //if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
+    //uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
+    AGSColor *palette = engine->GetPalette ();
+    int i=0;
+    int add_r,add_b,add_g = 0;
+    char ralpha = alpha>>2;
+    //if (ralpha > alpha) engine->AbortGame ("wtf");
+    //add_r = (((palette[fg].r>>1) * (alpha))>>8);
+    //add_b = (((palette[fg].b>>1) * (alpha))>>8);
+    //add_g = (((palette[fg].g)    * (alpha))>>8);
+    add_r = ((alphamultiply[(palette[fg].r>>1)*64+ralpha])>>6);
+    add_b = ((alphamultiply[(palette[fg].b>>1)*64+ralpha])>>6);
+    add_g = ((alphamultiply[(palette[fg].g   )*64+ralpha])>>6);
+    int out_r = min(31,(palette[bg].r>>1) + add_r);
+    int out_g = min(63, palette[bg].g     + add_g);
+    int out_b = min(31,(palette[bg].b>>1) + add_b);
+    i = ((out_r << 11) | (out_g << 5) | out_b);
+    unsigned char (*clutp) = clut;
+    unsigned char result = cycle_remap [*(clutp+i)]; //Once again, to make sure that the palette slot used is the right one.
+    //unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
+    //engine->ReleaseBitmapSurface (clutspr);
+    return result;
+}
+*/
+unsigned char GetColor565(unsigned char r, unsigned char g, unsigned char b) {
+	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
+	//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
+	//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
+	int i = ((r << 11) | (g << 5) | b);
+	unsigned char *clutp = clut;
+	unsigned char result = *(clutp + i);
+	result = cycle_remap [result]; //Once again, to make sure that the palette slot used is the right one.
+	//engine->ReleaseBitmapSurface (clutspr);
+	return result;
+}
+
+void CycleRemap(int start, int end) {
+	if (end > start) {
+		// Rotate left
+		int wraparound = cycle_remap [start];
+		for (; start < end; ++start) {
+			cycle_remap [start] = cycle_remap [start + 1];
+		}
+		cycle_remap [end] = wraparound;
+	} else if (end < start) {
+		// Rotate right
+		int wraparound = cycle_remap [start];
+		for (; start > end; --start) {
+			cycle_remap [start] = cycle_remap [start - 1];
+		}
+		cycle_remap [end] = wraparound;
+
+	}
+}
+
+unsigned char GetRemappedSlot(unsigned char slot) {
+	return cycle_remap [slot];
+}
+
+int LoadCLUT(int slot) {
+	if (engine->GetSpriteWidth(slot) != 256 || engine->GetSpriteHeight(slot) != 256) return 1;
+	BITMAP *clutimage = engine->GetSpriteGraphic(slot);
+	uint8 *clutarray = engine->GetRawBitmapSurface(clutimage);
+	int pitch = engine->GetBitmapPitch(clutimage);
+	for (int y = 0, arrayy = 0, cluty = 0; y < 256; y++, arrayy += pitch, cluty += 256) {
+		for (int x = 0; x < 256; x++) {
+			clut[cluty + x] = clutarray[arrayy + x];
+		}
+	}
+	clutslot = slot;
+	engine->ReleaseBitmapSurface(clutimage);
+	return 0;
+}
+
+void SetReflections(int toggle) {
+	drawreflections = toggle;
+}
+
+int IsReflectionsOn() {
+	return drawreflections;
+}
+
+int GetLuminosityFromPalette(int slot) {
+	AGSColor *pal = engine->GetPalette();
+	int lum = (pal[slot].r +
+	           pal[slot].r +
+	           pal[slot].r +
+	           pal[slot].g +
+	           pal[slot].g +
+	           pal[slot].g +
+	           pal[slot].g +
+	           pal[slot].b) >> 3;
+	return lum;
+}
+
+
+
+void SetStarsOriginPoint(int x, int y) {
+	Starfield.originx = x;
+	Starfield.originy = y;
+}
+void InitializeStars(int slot, int maxstars) {
+	int32 sw, sh = 0;
+	BITMAP *canvas = engine->GetSpriteGraphic(slot);
+	engine->GetBitmapDimensions(canvas, &sw, &sh, nullptr);
+	Starfield.maxstars = maxstars;
+	Starfield.overscan = 20;
+	stars = new starstype [Starfield.maxstars];
+	for (int i = 0; i < Starfield.maxstars; i++) {
+		stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
+		if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
+		stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
+		if (stars[i].y < 1.0 && stars[i].y > -1.0) stars[i].y = (float)sh;
+		stars[i].z = (float)(MAX_DEPTH);
+		stars[i].color = (::AGS::g_vm->getRandomNumber(0x7fffffff) % 240);
+		stars[i].sprite = 0;
+		stars[i].maxrad = (::AGS::g_vm->getRandomNumber(0x7fffffff) % 5);
+	}
+}
+
+void IterateStars(int slot) {
+	long sw, sh = 0;
+	sw = engine->GetSpriteWidth(slot);
+	sh = engine->GetSpriteHeight(slot);
+	for (int i = 0; i < Starfield.maxstars; i++) {
+		stars[i].z -= Starfield.speed;
+		//if (stars[i].z < 1.0) stars[i].z = (double)MAX_DEPTH;
+		float k = Starfield.depthmultiplier / stars[i].z;
+		int px = static_cast<int>(stars[i].x * k + Starfield.originx);
+		int py = static_cast<int>(stars[i].y * k + Starfield.originy);
+		if (px >= sw + Starfield.overscan || px < 0 - Starfield.overscan || py >= sh + Starfield.overscan || py < 0 - Starfield.overscan) {
+			stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
+			if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
+			stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
+			if (stars[i].y < 1.0 && stars[i].y > 1.0) stars[i].y = (float)sh;
+			stars[i].z = (float)MAX_DEPTH;
+			//stars[i].color = (rand () %240);
+		}
+	}
+}
+int GetStarfieldOverscan() {
+	return Starfield.overscan;
+}
+void SetStarfieldOverscan(int overscan) {
+	Starfield.overscan = overscan;
+}
+
+int GetStarfieldOriginX() {
+	return Starfield.originx;
+}
+
+int GetStarfieldOriginY() {
+	return Starfield.originy;
+}
+
+void SetStarfieldDepthMultiplier(int multi) {
+	Starfield.depthmultiplier = multi;
+}
+
+int GetStarfieldDepthMultiplier() {
+	return Starfield.depthmultiplier;
+}
+
+int GetStarfieldMaxStars() {
+	return Starfield.maxstars;
+}
+
+void SetStarSpriteScaleBoost(int star, int boost) {
+	stars[star].scaleboost = boost;
+}
+
+int GetStarSpriteScaleBoost(int star) {
+	return stars[star].scaleboost;
+}
+
+void SetStarMaxRadius(int star, int radius) {
+	stars[star].maxrad = radius;
+}
+
+int GetStarMaxRadius(int star) {
+	return stars[star].maxrad;
+}
+
+void RotateStar(int star, int angle, int px, int py) {
+	float rsin = rot_sine_LUT[angle];
+	float rcos = rot_cos_LUT[angle];
+	float fPx = (float)px;
+	float fPy = (float)py;
+	float x1 = 0, y1 = 0, xRot = 0, yRot = 0;
+	int i = star;
+	x1 = stars[i].x;
+	y1 = stars[i].y;
+	xRot = fPx + rcos * (x1 - fPx) - rsin * (y1 - fPy);
+	yRot = fPy + rsin * (x1 - fPx) + rcos * (y1 - fPy);
+	stars[i].x = xRot;
+	stars[i].y = yRot;
+	i++;
+}
+
+FLOAT_RETURN_TYPE GetStarX(int i) {
+	float starx = (float)stars[i].x;
+	RETURN_FLOAT(starx);
+}
+
+FLOAT_RETURN_TYPE GetStarY(int i) {
+	float stary = (float)stars[i].y;
+	RETURN_FLOAT(stary);
+}
+
+FLOAT_RETURN_TYPE GetStarZ(int i) {
+	float starz = (float)stars[i].z;
+	RETURN_FLOAT(starz);
+}
+
+void SetStarPosition(int star, SCRIPT_FLOAT(x), SCRIPT_FLOAT(y), SCRIPT_FLOAT(z)) {
+	INIT_SCRIPT_FLOAT(x);
+	INIT_SCRIPT_FLOAT(y);
+	INIT_SCRIPT_FLOAT(z);
+	stars[star].x = x;
+	stars[star].y = y;
+	stars[star].z = z;
+}
+
+void SetStarColor(int star, unsigned char color) {
+	stars[star].color = color;
+}
+
+unsigned char GetStarColor(int star) {
+	return stars[star].color;
+}
+
+void SetStarSprite(int star, int slot) {
+	stars[star].sprite = slot;
+}
+
+int GetStarSprite(int star) {
+	return stars[star].sprite;
+}
+
+void SetStarSpriteRange(int start, int end, int slot) {
+	int sfix = start;
+	int efix = end;
+	if (start > Starfield.maxstars) sfix = Starfield.maxstars - 1;
+	if (end > Starfield.maxstars) efix = Starfield.maxstars;
+	for (int i = sfix; i < efix; i++)
+		stars[i].sprite = slot;
+}
+
+void DrawStars(int slot, int maskslot) {
+	int32 sw, sh = 0;
+	BITMAP *canvas = engine->GetSpriteGraphic(slot);
+	if (!canvas) engine->AbortGame("DrawStars: Can't load sprite slot.");
+	BITMAP *maskcanvas = engine->GetSpriteGraphic(maskslot);
+	if (!maskcanvas) engine->AbortGame("DrawStars: Can't load mask slot.");
+	engine->GetBitmapDimensions(canvas, &sw, &sh, nullptr);
+	uint8 *screenarray = engine->GetRawBitmapSurface(canvas);
+	uint8 *maskarray = engine->GetRawBitmapSurface(maskcanvas);
+	int screenPitch = engine->GetBitmapPitch(canvas);
+	int maskPitch = engine->GetBitmapPitch(maskcanvas);
+	for (int i = 0; i < Starfield.maxstars; i++) {
+		//stars[i].z-= 0.5;
+		//if (stars[i].z < 1.0) stars[i].z = (double)MAX_DEPTH;
+		float k = (float)Starfield.depthmultiplier / stars[i].z;
+		int px = static_cast<int>(stars[i].x * k + Starfield.originx);
+		int py = static_cast<int>(stars[i].y * k + Starfield.originy);
+		if (px >= sw + Starfield.overscan || px < 0 - Starfield.overscan || py >= sh + Starfield.overscan || py < 0 - Starfield.overscan) {
+			stars[i].x = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sw) << 1) - sw;
+			if (stars[i].x < 1.0 && stars[i].x > -1.0) stars[i].x = (float)sw;
+			stars[i].y = (float)((::AGS::g_vm->getRandomNumber(0x7fffffff) % sh) << 1) - sh;
+			if (stars[i].y < 1.0 && stars[i].y > 1.0) stars[i].y = (float)sh;
+			stars[i].z = (float)MAX_DEPTH;
+			//stars[i].color = (rand () %240);
+		} else if (stars[i].z > 0) {
+			int ivalue = (63 - (int)stars[i].z);
+			if (ivalue > 63) ivalue = 63;
+			else if (ivalue < 0) ivalue = 0;
+			unsigned char value = (unsigned char)(ivalue);
+			unsigned char maskcolor = value << 2;
+			if (stars[i].sprite > 0) {
+				BITMAP *origspr = engine->GetSpriteGraphic(stars[i].sprite);
+				int scale = (ivalue + 1) * 100 >> 6;
+				//int scale = 50;
+				if (scale < 1) scale = 1;
+				/*
+				if (scale != 100)
+				{
+				uint8 * orig = engine->GetRawBitmapSurface (origspr);
+				int origPitch = engine->GetBitmapPitch(origspr);
+				int32 h1,h2,w1,w2=0;
+				double fw2,fh2;
+				engine->GetBitmapDimensions (origspr,&w1,&h1,NULL);
+				fh2 = h1 * (scale / 100.0);
+				fw2 = w1 * (scale / 100.0);
+				h2 = static_cast<int>(fh2);
+				w2 = static_cast<int>(fw2);
+				if (w2 < 1) w2 = 1;
+				if (h2 < 1) h2 = 1;
+				resizspr = engine->CreateBlankBitmap (w2,h2,8);
+				uint8 * resized = engine->GetRawBitmapSurface (resizspr);
+				int resizePitch = engine->GetBitmapPitch(resizspr);
+				int x_ratio = (int)((w1<<16)/w2) +1;
+				int y_ratio = (int)((h1<<16)/h2) +1;
+				int x2, y2 ;
+				for (int i=0;i<h2;i++)
+				{
+				    for (int j=0;j<w2;j++)
+				   {
+				       x2 = ((j*x_ratio)>>16) ;
+				       y2 = ((i*y_ratio)>>16) ;
+				       resized [i * resizePitch + j] = orig [y2 * origPitch + x2];
+				 }
+				}
+				engine->ReleaseBitmapSurface (resizspr);
+				}
+				//resizspr = origspr;
+				int32 w,h=0;
+				engine->GetBitmapDimensions (resizspr,&w,&h,NULL);
+				uint8 *imagemap = engine->GetRawBitmapSurface (resizspr);
+				int imagePitch = engine->GetBitmapPitch(resizspr);
+				int ox = px - (w>>1);
+				int oy = py - (h>>1);
+				for (int dy=0;dy<h;dy++)
+				{
+				for (int dx=0;dx<w;dx++)
+				{
+				   int ex = ox+dx;
+				   int ey = oy+dy;
+				   if (ex < sw && ex >= 0 && ey < sh && ey >= 0)
+				   {
+				       if (maskcolor > maskarray [ey * maskPitch + ex] && imagemap[dy * imagePitch + dx] > 0)
+				       {
+				           maskarray [ey * maskPitch + ex] = maskcolor;
+				           screenarray [ey * screenPitch + ex] = imagemap[dy][dx];
+				       }
+				   }
+				}
+				}
+				*/
+
+				uint8 *orig = engine->GetRawBitmapSurface(origspr);
+				int origPitch = engine->GetBitmapPitch(origspr);
+				int32 h1, h2, w1, w2 = 0;
+				double fw2, fh2;
+				engine->GetBitmapDimensions(origspr, &w1, &h1, nullptr);
+				fh2 = h1 * (scale / 100.0);
+				fw2 = w1 * (scale / 100.0);
+				h2 = static_cast<int>(fh2);
+				w2 = static_cast<int>(fw2);
+				if (w2 < 1) w2 = 1;
+				if (h2 < 1) h2 = 1;
+				int x_ratio = (int)((w1 << 16) / w2) + 1;
+				int y_ratio = (int)((h1 << 16) / h2) + 1;
+				int x2, y2 ;
+				int ox = px - (w2 >> 1);
+				int oy = py - (h2 >> 1);
+				for (int ii = 0; ii < h2; ii++) {
+					int temprzy = ii * y_ratio;
+					int ey = oy + ii;
+					for (int j = 0; j < w2; j++) {
+						x2 = ((j * x_ratio) >> 16);
+						y2 = ((temprzy) >> 16);
+						int ex = ox + j;
+						if (ex < sw && ex >= 0 && ey < sh && ey >= 0) {
+							if (maskcolor > maskarray [ey * maskPitch + ex] && orig[y2 * origPitch + x2] > 0) {
+								maskarray [ey * maskPitch + ex] = maskcolor;
+								screenarray [ey * screenPitch + ex] = orig[y2 * origPitch + x2];
+							}
+						}
+						//resized [ii][j] = orig [y2 * origPitch + x2];
+					}
+				}
+				engine->ReleaseBitmapSurface(origspr);
+			} else if (stars[i].sprite == 0) {
+				if (stars[i].maxrad == 1) {
+					if (px < sw && px >= 0 && py < sh && py >= 0) {
+						if (maskcolor > maskarray[py * maskPitch + px]) {
+							maskarray[py * maskPitch + px] = maskcolor;
+							screenarray[py * screenPitch + px] = stars[i].color;
+						}
+					}
+				} else {
+					int scale = ((((int)stars[i].z) * 100) / 63);
+					if (scale < 1) scale = 1;
+					int radius = (stars[i].maxrad * (100 - scale) / 100);
+					int radsq = radius * radius;
+					//unsigned char color = GetColor565 (value>>1,value,value>>1);
+					unsigned char color = stars[i].color;
+					for (int cy = -radius; cy <= radius; cy++) { //Draw a circle around the point, for the mask.
+						int cysq = cy * cy;
+						for (int cx = -radius; cx <= radius; cx++) {
+							int cxsq = cx * cx;
+							int dx = cx + px;
+							int dy = cy + py;
+							if ((cxsq + cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0) {
+								if (maskcolor > maskarray [dy * maskPitch + dx]) {
+									maskarray [dy * maskPitch + dx] = maskcolor;
+									screenarray [dy * screenPitch + dx] = color;
+								}
+							}
+						}
+					}
+					/*
+					for(int cy=-radius; cy<=radius; cy++) //Draw a circle around the point, for the color.
+					{
+					   int cysq = cy*cy;
+					for(int cx=-radius; cx<=radius; cx++)
+					   {
+					       int cxsq = cx*cx;
+					       int dx = cx+px;
+					       int dy = cy+py;
+					       if((cxsq+cysq <= radsq) && dx < sw && dx >= 0 && dy < sh && dy >= 0)
+					       {
+					           if (maskarray [dy * maskPitch + dx] == maskcolor)screenarray [dy * screenPitch + dx] = color;
+					       }
+					   }
+					}
+					*/
+				}
+			}
+		}
+	}
+	engine->ReleaseBitmapSurface(canvas);
+	engine->ReleaseBitmapSurface(maskcanvas);
+	engine->NotifySpriteUpdated(slot);
+	engine->NotifySpriteUpdated(maskslot);
+}
+
+
+int CreateTranslucentOverlay(int id, int spriteId, int alpha, int level, int ox, int oy, int mask = 0, int blendmode = 0) {
+	BITMAP *testspr = engine->GetSpriteGraphic(spriteId);
+	if (testspr) overlay[id].sprite = spriteId;
+	else engine->AbortGame("CreateTranslucentOverlay: Invalid spriteId.");
+	engine->ReleaseBitmapSurface(testspr);
+	overlay[id].level = MAX(0, MIN(level, 4));
+	overlay[id].trans = MAX(0, MIN(alpha, 255));
+	overlay[id].spritemask = mask;
+	overlay[id].x = ox;
+	overlay[id].y = oy;
+	overlay[id].enabled = true;
+	overlay[id].blendtype = blendmode;
+	return 0;
+}
+
+int DeleteTranslucentOverlay(int id) {
+	overlay[id].enabled = false;
+	overlay[id].sprite = 0;
+	overlay[id].x = 0;
+	overlay[id].y = 0;
+	overlay[id].level = 0;
+	overlay[id].trans = 0;
+	return 0;
+}
+
+int MoveTranslucentOverlay(int id, int ox, int oy) {
+	overlay[id].x = ox;
+	overlay[id].y = oy;
+	return 0;
+}
+
+int GetTranslucentOverlayX(int id) {
+	return overlay[id].x;
+}
+
+int GetTranslucentOverlayY(int id) {
+	return overlay[id].y;
+}
+
+int GetTranslucentOverlaySprite(int id) {
+	return overlay[id].sprite;
+}
+
+int GetTranslucentOverlayLevel(int id) {
+	return overlay[id].level;
+}
+
+int GetTranslucentOverlayEnabled(int id) {
+	return overlay[id].enabled;
+}
+
+int GetTranslucentOverlayAlpha(int id) {
+	return overlay[id].trans;
+}
+
+int SetTranslucentOverlayAlpha(int id, int alpha) {
+	if (alpha >= 0 && alpha < 256)
+		overlay[id].trans = alpha;
+	else
+		engine->AbortGame("CreateTranslucentOverlay: Invalid alpha selected.");
+	return 0;
+}
+
+int SetTranslucentOverlayEnabled(int id, int toggle) {
+	if (toggle > 0)
+		overlay[id].enabled = true;
+	else
+		overlay[id].enabled = false;
+	return 0;
+}
+
+void SetCharacterReflected(int id, int refl) {
+	if (refl > 0) Reflection.Characters[id].reflect = 1;
+	else Reflection.Characters[id].reflect = 0;
+}
+
+void SetObjectReflected(int id, int refl) {
+	if (refl > 0)
+		Reflection.Objects[id].reflect = 1;
+	else
+		Reflection.Objects[id].reflect = 0;
+}
+
+int GetCharacterReflected(int id) {
+	return Reflection.Characters[id].reflect;
+}
+
+int GetObjectReflected(int id) {
+	return Reflection.Objects[id].reflect;
+}
+
+void ReplaceCharacterReflectionView(int id, int view) {
+	Reflection.Characters[id].replaceview = view - 1;
+}
+
+void SetObjectReflectionIgnoreScaling(int id, int wb) {
+	if (wb) Reflection.Objects[id].ignorescaling = 1;
+	else    Reflection.Objects[id].ignorescaling = 0;
+}
+
+int DrawReflections(int id, int charobj = 0) {
+	int32 screenw, screenh;
+	int32 bgw, bgh;
+	engine->GetScreenDimensions(&screenw, &screenh, nullptr);
+	BITMAP *bgmask = engine->GetBackgroundScene(1);
+	if (bgmask == nullptr) return 1;
+	//BITMAP *virtsc = engine->GetVirtualScreen();
+	BITMAP *walkbehind = engine->GetRoomMask(MASK_WALKBEHIND);
+	//if (!virtsc) engine->AbortGame ("Can't load virtual screen.");
+	if (!walkbehind) engine->AbortGame("DrawRelfections: Can't load Walkbehind into memory.");
+	engine->GetBitmapDimensions(walkbehind, &bgw, &bgh, nullptr);
+	if (!bgmask) engine->AbortGame("DrawReflections: Can't load reflection mask.");
+	//unsigned char **charbuffer = engine->GetRawBitmapSurface (virtsc);
+	uint8 *wbarray = engine->GetRawBitmapSurface(walkbehind);
+	uint8 *maskarray = engine->GetRawBitmapSurface(bgmask);
+	int wbPitch = engine->GetBitmapPitch(walkbehind);
+	int maskPitch = engine->GetBitmapPitch(bgmask);
+	//Initialize stuff
+	BITMAP *charsprite = nullptr;
+	BITMAP *charsprite2 = nullptr;
+	AGSCharacter *currchar = nullptr;
+	AGSObject *currobj;
+	int cox = 0, coy = 0, coz = 0;
+	int scale = 0;
+	//Get character, and their sprite.
+	if (charobj == 0) {
+		currchar = engine->GetCharacter(id);
+		/*int view = 0;
+		if (Reflection.Characters[id].replaceview == 0) view = currchar->view + 1;
+		else view = Reflection.Characters[id].replaceview;
+		*/
+		AGSViewFrame *vf = engine->GetViewFrame(currchar->view + 1, currchar->loop, currchar->frame);
+		charsprite = engine->GetSpriteGraphic(vf->pic);
+		long scaling = currchar->flags & CHF_NOSCALING;
+		if (!scaling)scale = engine->GetAreaScaling(currchar->x, currchar->y);
+		else scale = 100;
+		cox = currchar->x;
+		coy = currchar->y;
+		coz = currchar->z;
+	} else if (charobj == 1) {
+		currobj = engine->GetObject(id);
+
+		charsprite = engine->GetSpriteGraphic(currobj->num);
+		if (Reflection.Objects[id].ignorescaling) scale = 100;
+		else scale = engine->GetAreaScaling(currobj->x, currobj->y);
+		cox = currobj->x;
+		if (currobj->baseline < 0) coy = currobj->y;
+		else coy = currobj->baseline;
+		coz = 0;
+	}
+	bool scaled = false;
+	int32 w, h;
+	engine->GetBitmapDimensions(charsprite, &w, &h, nullptr);
+	if (scale != 100) {
+		uint8 *orig = engine->GetRawBitmapSurface(charsprite);
+		int origPitch = engine->GetBitmapPitch(charsprite);
+		int h1, h2, w1, w2;
+		double fw2, fh2;
+		h1 = h;
+		w1 = w;
+		fh2 = h1 * ((double)scale / 100.0);
+		fw2 = w1 * ((double)scale / 100.0);
+		h2 = static_cast<int>(fh2);
+		w2 = static_cast<int>(fw2);
+		charsprite2 = engine->CreateBlankBitmap(w2, h2, 8);
+		uint8 *resized = engine->GetRawBitmapSurface(charsprite2);
+		int resizedPitch = engine->GetBitmapPitch(charsprite2);
+		int x_ratio = (int)((w1 << 16) / w2) + 1;
+		int y_ratio = (int)((h1 << 16) / h2) + 1;
+		int x2, y2 ;
+		for (int i = 0; i < h2; i++) {
+			for (int j = 0; j < w2; j++) {
+				x2 = ((j * x_ratio) >> 16) ;
+				y2 = ((i * y_ratio) >> 16) ;
+				resized [i * resizedPitch + j] = orig [y2 * origPitch + x2];
+			}
+		}
+		engine->ReleaseBitmapSurface(charsprite2);
+		scaled = true;
+		w = w2;
+		h = h2;
+	} else {
+		charsprite2 = charsprite;
+	}
+	int transamount = 0;
+	uint8 *spritearray = engine->GetRawBitmapSurface(charsprite2);
+	uint8 *charbuffer = engine->GetRawBitmapSurface(rcolormap);
+	uint8 *alphaarray = engine->GetRawBitmapSurface(ralphamap);
+	int spritePitch = engine->GetBitmapPitch(charsprite2);
+	int charPitch = engine->GetBitmapPitch(rcolormap);
+	int alphaPitch = engine->GetBitmapPitch(ralphamap);
+	int i = h - 1, j = 0;
+	int32 ox = cox;
+	if (charobj == 0) ox = ox - (w / 2);
+	int32 oy = coy + coz - 1;
+	engine->RoomToViewport(&ox, &oy);
+	int yoffset = 0;
+	int translevel = 7;
+	//bool dither = false;
+	//bool dodither = false;
+	int counter = 0;
+	int rowcount = 101 - (int)(50.0 * ((double)(scale) / 100.0));
+	int delay = screenh / rowcount;
+	int *obst;
+	int flipped = 0;
+	if (charobj == 0) {
+		int (*sfGetGameParameter)(int, int, int, int);
+		sfGetGameParameter = ((int(*)(int, int, int, int)) engine->GetScriptFunctionAddress("GetGameParameter"));
+		flipped = sfGetGameParameter(13, currchar->view + 1, currchar->loop, currchar->frame);
+	} else flipped = 0;
+	obst = new int [w];
+	for (int k = 0; k < w; k++) {
+		obst[k] = 0;
+	}
+	while (i > 0) {
+		//if ((counter == delay/2-1 || counter == delay-1) && yoffset < 36) dodither = (!dodither);
+		if (counter == delay) {
+			counter = 0;
+			if (translevel > 0) translevel--;
+		} else counter++;
+		yoffset++;
+		while (j < w) {
+			int xoffset;
+			if (flipped == 1) xoffset = w - j - 1;
+			else xoffset = j;
+			int32 rx = ox + xoffset, ry = oy + yoffset;
+			int wbb = 0;
+			engine->ViewportToRoom(&rx, &ry);
+			if (ry > 0 && ry < bgh && rx > 0 && rx < bgw) {
+				if (wbarray [ry * wbPitch + rx] > 0) {
+					wbb = engine->GetWalkbehindBaseline(wbarray[ry * wbPitch + rx]);
+				}
+				if (maskarray[ry * maskPitch + rx] == 21) obst[j] = 1;
+			}
+
+			//dither = (!dither);
+			transamount = 32 * translevel;
+			if (spritearray [i * spritePitch + j] != 0 && oy + yoffset < screenh && ox + xoffset < screenw && oy + yoffset >= 0 && ox + xoffset >= 0) { // If the sprite isn't transparent, and isn't drawn off the edge of the bg.
+				if (wbb < ry && obst[j] == 0 && (oy > reflectionmap[(ox + xoffset) + (screenw * (oy + yoffset))])) {
+					//charbuffer[(oy+yoffset) * charPitch + ox+xoffset] = MixColorAlpha (spritearray [i * spritePitch + j],charbuffer[(oy+yoffset) * charPitch + ox+xoffset],transamount);
+					charbuffer [(oy + yoffset) * charPitch + ox + xoffset] = spritearray [i * spritePitch + j];
+					alphaarray [(oy + yoffset) * alphaPitch + ox + xoffset] = transamount;
+					reflectionmap[(ox + xoffset) + (screenw * (oy + yoffset))] = oy;
+				}
+			}
+			j++;
+		}
+		//if (w % 2 == 0) dither = (!dither);
+		i--;
+		j = 0;
+	}
+
+	delete [] obst;
+	if (scaled == true)engine->FreeBitmap(charsprite2);
+	engine->ReleaseBitmapSurface(charsprite);
+	//engine->ReleaseBitmapSurface (virtsc);
+	//engine->ReleaseBitmapSurface (clutspr);
+	engine->ReleaseBitmapSurface(bgmask);
+	engine->ReleaseBitmapSurface(walkbehind);
+	engine->ReleaseBitmapSurface(rcolormap);
+	engine->ReleaseBitmapSurface(ralphamap);
+	engine->MarkRegionDirty(ox, oy, ox + w, oy + h);
+	return 0;
+}
+
+
+int DrawTransSprite(int spriteId, int bg, int translevel, int mask = 0, int blendmode = 0, int use_objpal = 0) {
+	BITMAP *maskspr = nullptr;
+	if (mask > 0) maskspr = engine->GetSpriteGraphic(mask);
+	if (!maskspr && mask > 0) {
+		char maskerr [100];
+		snprintf(maskerr, 100, "DrawTransSprite: Can't load mask from slot %d.", mask);
+		engine->AbortGame(maskerr);
+	}
+	// Get a reference to the screen we'll draw onto
+	BITMAP *bgspr = engine->GetSpriteGraphic(bg);
+	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
+	BITMAP *spritespr = engine->GetSpriteGraphic(spriteId);
+	if (!bgspr) engine->AbortGame("DrawTransSprite: Can't load background");
+	//if (!clutspr) engine->AbortGame ("Can't load CLUT spriteId into memory.");
+	if (!spritespr) engine->AbortGame("DrawTransSprite: Can't load overlay spriteId into memory.");
+	// Get its surface
+	int32 sprw, sprh, coldepth;
+	int32 bgw, bgh;
+	engine->GetBitmapDimensions(bgspr, &bgw, &bgh, &coldepth);
+	engine->GetBitmapDimensions(spritespr, &sprw, &sprh, &coldepth);
+
+	uint8 *bgarray = engine->GetRawBitmapSurface(bgspr);
+	//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
+	uint8 *spritearray = engine->GetRawBitmapSurface(spritespr);
+	int bgPitch = engine->GetBitmapPitch(bgspr);
+	//int clutPitch = engine->GetBitmapPitch(clutspr);
+	int spritePitch = engine->GetBitmapPitch(spritespr);
+
+	unsigned char *maskarray = nullptr;
+	int maskPitch = 0;
+	if (mask > 0) {
+		maskarray = engine->GetRawBitmapSurface(maskspr);
+		maskPitch = engine->GetBitmapPitch(maskspr);
+	}
+	int tloffset = 255 - translevel;
+	int x = 0;
+	int y = 0;
+	//int transamount = 256 * translevel; //old
+	while (y < sprh) {
+		while (x < sprw) {
+			if (spritearray [y * spritePitch + x] != 0 && y < bgh && x < bgw && y >= 0 && x >= 0) { // If the spriteId isn't transparent, and isn't drawn off the edge of the bg.
+				if (mask > 0) {
+					translevel = MAX(maskarray [y * maskPitch + x] - tloffset, 0);
+				}
+				//spritearray[y * spritePitch + x] = cycle_remap[clutarray [(cycle_remap[bgarray[y * bgPitch + x]]+transamount) * clutPitch + (cycle_remap[spritearray [y * spritePitch + x]])]; //old
+				if (blendmode == 0) spritearray[y * spritePitch + x] = Mix::MixColorAlpha(spritearray [y * spritePitch + x], bgarray[y * bgPitch + x], translevel, use_objpal);
+				else if (blendmode == 1) spritearray[y * spritePitch + x] = Mix::MixColorAdditive(spritearray [y * spritePitch + x], bgarray[y * bgPitch + x], translevel, use_objpal);
+			}
+			x++;
+		}
+		x = 0;
+		y++;
+	}
+
+	// Release the screen so that the engine can continue
+	engine->ReleaseBitmapSurface(bgspr);
+	//engine->ReleaseBitmapSurface (clutspr);
+	engine->ReleaseBitmapSurface(spritespr);
+	engine->NotifySpriteUpdated(spriteId);
+	return 0;
+}
+
+int DrawTranslucentOverlay(int spriteId, int translevel, int ox, int oy, int mask = 0, int blendmode = 0) {
+	if (translevel == 0) return 0;
+	BITMAP *maskspr = nullptr;
+	// Get a reference to the screen we'll draw onto
+	BITMAP *virtsc = engine->GetVirtualScreen();
+	//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
+	BITMAP *spritespr = engine->GetSpriteGraphic(spriteId);
+	if (mask > 0) maskspr = engine->GetSpriteGraphic(mask);
+	if (!virtsc) engine->AbortGame("DrawTranslucentOverlay: Can't load virtual screen.");
+	//if (!clutspr) engine->AbortGame ("Can't load CLUT spriteId into memory.");
+	if (!spritespr) engine->AbortGame("DrawTranslucentOverlay: Can't load overlay spriteId into memory.");
+	// Get its surface
+	int32 sprw, sprh, coldepth;
+	int32 screenw, screenh;
+	engine->GetScreenDimensions(&screenw, &screenh, &coldepth);
+	engine->GetBitmapDimensions(spritespr, &sprw, &sprh, &coldepth);
+	uint8 *charbuffer = engine->GetRawBitmapSurface(virtsc);
+	uint8 *spritearray = engine->GetRawBitmapSurface(spritespr);
+	int charPitch = engine->GetBitmapPitch(virtsc);
+	int spritePitch = engine->GetBitmapPitch(spritespr);
+	uint8 *maskarray = nullptr;
+	int maskPitch = 0;
+	if (mask > 0) {
+		if (!maskspr && mask > 0) {
+			char maskerr [100];
+			snprintf(maskerr, 100, "DrawTransSprite: Can't load mask from slot %d.", mask);
+			engine->AbortGame(maskerr);
+		}
+		maskarray = engine->GetRawBitmapSurface(maskspr);
+		maskPitch = engine->GetBitmapPitch(maskspr);
+	}
+	int tloffset = 255 - translevel;
+	int x = 0;
+	int y = 0;
+	//int transamount = 256 * translevel; //old
+	while (y < sprh) {
+		while (x < sprw) {
+			if (spritearray [y * spritePitch + x] != 0 && y + oy < screenh && x + ox < screenw && y + oy >= 0 && x + ox >= 0) { // If the spriteId isn't transparent, and isn't drawn off the edge of the screen.
+				//charbuffer[(y+oy) * charPitch + x+ox] = cycle_remap[clutarray ([cycle_remap[charbuffer[(y+oy) * charPitch + x+ox]]+transamount) * clutPitch + (cycle_remap[spritearray [y * spritePitch + x]])]; //old
+				if (mask > 0) {
+					translevel = MAX(maskarray [y * maskPitch + x] - tloffset, 0);
+				}
+				if (blendmode == 0) {
+					if (translevel == 255) {
+						charbuffer[(y + oy) * charPitch + x + ox] = spritearray [y * spritePitch + x];
+					} else charbuffer[(y + oy) * charPitch + x + ox] = Mix::MixColorAlpha(spritearray [y * spritePitch + x], charbuffer[(y + oy) * charPitch + x + ox], translevel);
+				} else if (blendmode == 1) charbuffer[(y + oy) * charPitch + x + ox] = Mix::MixColorAdditive(spritearray [y * spritePitch + x], charbuffer[(y + oy) * charPitch + x + ox], translevel);
+			}
+			x++;
+		}
+		x = 0;
+		y++;
+	}
+
+	// Release the screen so that the engine can continue
+	long dirtywidth = ox + sprw;
+	if (dirtywidth > screenw) dirtywidth = screenw - 1;
+	long dirtyheight = oy + sprh;
+	if (dirtyheight > screenh) dirtywidth = screenh - 1;
+	engine->ReleaseBitmapSurface(virtsc);
+	//engine->ReleaseBitmapSurface (clutspr);
+	engine->ReleaseBitmapSurface(spritespr);
+	if (mask > 0) engine->ReleaseBitmapSurface(maskspr);
+	engine->MarkRegionDirty(ox, oy, dirtywidth, dirtyheight);
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+
+AGSPalRender::AGSPalRender() : PluginBase() {
+	DLL_METHOD(AGS_GetPluginName);
+	DLL_METHOD(AGS_EngineStartup);
+	DLL_METHOD(AGS_EngineShutdown);
+	DLL_METHOD(AGS_EngineOnEvent);
+}
+
+const char *AGSPalRender::AGS_GetPluginName() {
+	return "PALgorithms Translucent Overlay Renderer";
+}
+
+void AGSPalRender::AGS_EngineStartup(IAGSEngine *lpEngine) {
+	engine = lpEngine;
+
+	// Make sure it's got the version with the features we need
+	if (engine->version < 3) {
+		engine->AbortGame("Engine interface is too old, need newer version of AGS.");
+	}
+	engine->RegisterScriptFunction("PALInternal::LoadCLUT^1", (void *)LoadCLUT);
+	engine->RegisterScriptFunction("PALInternal::CycleRemap^2", (void *)CycleRemap);
+	engine->RegisterScriptFunction("PALInternal::GetColor565^3", (void *)GetColor565);
+	engine->RegisterScriptFunction("PALInternal::GetLuminosityFromPalette^1", (void *)GetLuminosityFromPalette);
+	engine->RegisterScriptFunction("PALInternal::FastSin^1", (void *)AGSFastSin);
+	engine->RegisterScriptFunction("PALInternal::FastCos^1", (void *)AGSFastCos);
+	engine->RegisterScriptFunction("PALInternal::FastRoot^1", (void *)root);
+	engine->RegisterScriptFunction("PALInternal::GetRemappedSlot^1", (void *)GetRemappedSlot);
+	engine->RegisterScriptFunction("PALInternal::ResetRemapping^0", (void *)ResetRemapping);
+	engine->RegisterScriptFunction("PALInternal::GetModifiedBackgroundImage", (void *)GetModifiedBackgroundImage);
+	engine->RegisterScriptFunction("PALInternal::WriteObjectivePalette^4", (void *)WriteObjectivePalette);
+	engine->RegisterScriptFunction("PALInternal::ReadObjectivePaletteR^1", (void *)ReadObjectivePaletteR);
+	engine->RegisterScriptFunction("PALInternal::ReadObjectivePaletteB^1", (void *)ReadObjectivePaletteB);
+	engine->RegisterScriptFunction("PALInternal::ReadObjectivePaletteG^1", (void *)ReadObjectivePaletteG);
+
+	engine->RegisterScriptFunction("Raycast::Render^1", (void *)Raycast_Render);
+	engine->RegisterScriptFunction("Raycast::LoadMap^4", (void *)LoadMap);
+	engine->RegisterScriptFunction("Raycast::Initialize", (void *)Init_Raycaster);
+	engine->RegisterScriptFunction("Raycast::MakeTextures^1", (void *)MakeTextures);
+	engine->RegisterScriptFunction("Raycast::MoveForward^0", (void *)MoveForward);
+	engine->RegisterScriptFunction("Raycast::MoveBackward^0", (void *)MoveBackward);
+	engine->RegisterScriptFunction("Raycast::RotateLeft^0", (void *)RotateLeft);
+	engine->RegisterScriptFunction("Raycast::RotateRight^0", (void *)RotateRight);
+	engine->RegisterScriptFunction("Raycast::SetCameraPosition^2", (void *)Ray_SetPlayerPosition);
+	engine->RegisterScriptFunction("Raycast::GetCameraX^0", (void *)Ray_GetPlayerX);
+	engine->RegisterScriptFunction("Raycast::GetCameraY^0", (void *)Ray_GetPlayerY);
+	engine->RegisterScriptFunction("Raycast::GetCameraAngle^0", (void *)Ray_GetPlayerAngle);
+	engine->RegisterScriptFunction("Raycast::SetCameraAngle^1", (void *)Ray_SetPlayerAngle);
+	engine->RegisterScriptFunction("Raycast::InitSprite^9", (void *)Ray_InitSprite);
+	engine->RegisterScriptFunction("Raycast::UnloadEngine^0", (void *)QuitCleanup);
+	engine->RegisterScriptFunction("Raycast::GetHotspotAtXY^2", (void *)Ray_GetHotspotAt);
+	engine->RegisterScriptFunction("Raycast::GetObjectAtXY^2", (void *)Ray_GetObjectAt);
+	engine->RegisterScriptFunction("Raycast::SetSpriteInteractObj^2", (void *)Ray_SetSpriteInteractObj);
+	engine->RegisterScriptFunction("Raycast::GetSpriteInteractObj^1", (void *)Ray_GetSpriteInteractObj);
+	engine->RegisterScriptFunction("Raycast::SetSpritePosition^3", (void *)Ray_SetSpritePosition);
+	engine->RegisterScriptFunction("Raycast::SetSpriteVertOffset^2", (void *)Ray_SetSpriteVertOffset);
+	engine->RegisterScriptFunction("Raycast::GetSpriteVertOffset^1", (void *)Ray_GetSpriteVertOffset);
+	engine->RegisterScriptFunction("Raycast::GetSpriteX^1", (void *)Ray_GetSpriteX);
+	engine->RegisterScriptFunction("Raycast::GetSpriteY^1", (void *)Ray_GetSpriteY);
+	engine->RegisterScriptFunction("Raycast::SetWallHotspot^2", (void *)Ray_SetWallHotspot);
+	engine->RegisterScriptFunction("Raycast::SetWallTextures^5", (void *)Ray_SetWallTextures);
+	engine->RegisterScriptFunction("Raycast::SetWallSolid^5", (void *)Ray_SetWallSolid);
+	engine->RegisterScriptFunction("Raycast::SetWallIgnoreLighting^5", (void *)Ray_SetWallIgnoreLighting);
+	engine->RegisterScriptFunction("Raycast::SetWallAlpha^5", (void *)Ray_SetWallAlpha);
+	engine->RegisterScriptFunction("Raycast::SetWallBlendType^5", (void *)Ray_SetWallBlendType);
+	engine->RegisterScriptFunction("Raycast::GetMoveSpeed^0", (void *)Ray_GetMoveSpeed);
+	engine->RegisterScriptFunction("Raycast::SetMoveSpeed^1", (void *)Ray_SetMoveSpeed);
+	engine->RegisterScriptFunction("Raycast::GetRotSpeed^0", (void *)Ray_GetRotSpeed);
+	engine->RegisterScriptFunction("Raycast::SetRotSpeed^1", (void *)Ray_SetRotSpeed);
+	engine->RegisterScriptFunction("Raycast::GetWallAt^2", (void *)Ray_GetWallAt);
+	engine->RegisterScriptFunction("Raycast::GetLightAt^2", (void *)Ray_GetLightAt);
+	engine->RegisterScriptFunction("Raycast::SetLightAt^3", (void *)Ray_SetLightAt);
+	engine->RegisterScriptFunction("Raycast::SetWallAt^3", (void *)Ray_SetWallAt);
+	engine->RegisterScriptFunction("Raycast::SetPlaneY^1", (void *)Ray_SetPlaneY);
+	engine->RegisterScriptFunction("Raycast::GetDistanceAt^2", (void *)Ray_GetDistanceAt);
+	engine->RegisterScriptFunction("Raycast::GetSpriteAngle^1", (void *)Ray_GetSpriteAngle);
+	engine->RegisterScriptFunction("Raycast::SetSpriteAngle^2", (void *)Ray_SetSpriteAngle);
+	engine->RegisterScriptFunction("Raycast::SetSpriteView^2", (void *)Ray_SetSpriteView);
+	engine->RegisterScriptFunction("Raycast::GetSpriteView^1", (void *)Ray_GetSpriteView);
+	engine->RegisterScriptFunction("Raycast::SetSpriteFrame^2", (void *)Ray_SetSpriteFrame);
+	engine->RegisterScriptFunction("Raycast::GetSpriteFrame^1", (void *)Ray_GetSpriteFrame);
+	engine->RegisterScriptFunction("Raycast::SetSpritePic^2", (void *)Ray_SetSpritePic);
+	engine->RegisterScriptFunction("Raycast::GetSpritePic^1", (void *)Ray_GetSpritePic);
+	engine->RegisterScriptFunction("Raycast::SetSkyBox^1", (void *)Ray_SetSkyBox);
+	engine->RegisterScriptFunction("Raycast::SetSpriteAlpha^2", (void *)Ray_SetSpriteAlpha);
+	engine->RegisterScriptFunction("Raycast::GetSpriteAlpha^1", (void *)Ray_GetSpriteAlpha);
+	engine->RegisterScriptFunction("Raycast::GetSkyBox^1", (void *)Ray_GetSkyBox);
+	engine->RegisterScriptFunction("Raycast::SetAmbientLight^1", (void *)Ray_SetAmbientLight);
+	engine->RegisterScriptFunction("Raycast::SetAmbientColor^2", (void *)Ray_SetAmbientColor);
+	engine->RegisterScriptFunction("Raycast::GetAmbientLight^0", (void *)Ray_GetAmbientLight);
+	engine->RegisterScriptFunction("Raycast::GetAmbientWeight^0", (void *)Ray_GetAmbientWeight);
+	engine->RegisterScriptFunction("Raycast::GetTileX_At^2", (void *)Ray_GetTileX_At);
+	engine->RegisterScriptFunction("Raycast::GetTileY_At^2", (void *)Ray_GetTileY_At);
+	engine->RegisterScriptFunction("Raycast::DrawTile^2", (void *)Ray_DrawTile);
+	engine->RegisterScriptFunction("Raycast::DrawOntoTile^2", (void *)Ray_DrawOntoTile);
+	engine->RegisterScriptFunction("Raycast::SetNoClip^1", (void *)Ray_SetNoClip);
+	engine->RegisterScriptFunction("Raycast::GetNoClip^0", (void *)Ray_GetNoClip);
+	engine->RegisterScriptFunction("Raycast::GetSpriteScaleX^1", (void *)Ray_GetSpriteScaleX);
+	engine->RegisterScriptFunction("Raycast::SetSpriteScaleX^2", (void *)Ray_SetSpriteScaleX);
+	engine->RegisterScriptFunction("Raycast::GetSpriteScaleY^1", (void *)Ray_GetSpriteScaleY);
+	engine->RegisterScriptFunction("Raycast::SetSpriteScaleY^2", (void *)Ray_SetSpriteScaleY);
+	engine->RegisterScriptFunction("Raycast::GetSpriteBlendType^1", (void *)Ray_GetSpriteBlendType);
+	engine->RegisterScriptFunction("Raycast::SetSpriteBlendType^2", (void *)Ray_SetSpriteBlendType);
+
+
+	engine->RegisterScriptFunction("Raycast::SetFloorAt^3", (void *)Ray_SetFloorAt);
+	engine->RegisterScriptFunction("Raycast::SetCeilingAt^3", (void *)Ray_SetCeilingAt);
+	engine->RegisterScriptFunction("Raycast::GetCeilingAt^2", (void *)Ray_GetCeilingAt);
+	engine->RegisterScriptFunction("Raycast::GetFloorAt^2", (void *)Ray_GetFloorAt);
+	engine->RegisterScriptFunction("Raycast::GetLightingAt^2", (void *)Ray_GetLightingAt);
+	engine->RegisterScriptFunction("Raycast::SetLightingAt^3", (void *)Ray_SetLightingAt);
+	engine->RegisterScriptFunction("Raycast::GetWallHotspot^1", (void *)Ray_GetWallHotspot);
+	engine->RegisterScriptFunction("Raycast::GetWallTexture^2", (void *)Ray_GetWallTexture);
+	engine->RegisterScriptFunction("Raycast::GetWallSolid^2", (void *)Ray_GetWallSolid);
+	engine->RegisterScriptFunction("Raycast::GetWallIgnoreLighting^2", (void *)Ray_GetWallIgnoreLighting);
+	engine->RegisterScriptFunction("Raycast::GetWallAlpha^2", (void *)Ray_GetWallAlpha);
+	engine->RegisterScriptFunction("Raycast::GetWallBlendType^2", (void *)Ray_GetWallBlendType);
+	engine->RegisterScriptFunction("Raycast::SelectTile^3", (void *)Ray_SelectTile);
+	engine->RegisterScriptFunction("Raycast::HasSeenTile^2", (void *)Ray_HasSeenTile);
+
+	engine->RegisterScriptFunction("LensDistort::SetPos^2", (void *)SetLensPos);
+	engine->RegisterScriptFunction("LensDistort::GetX^0", (void *)GetLensX);
+	engine->RegisterScriptFunction("LensDistort::GetY^0", (void *)GetLensY);
+	engine->RegisterScriptFunction("LensDistort::Set^1", (void *)SetLensDrawn);
+	engine->RegisterScriptFunction("LensDistort::IsDrawn^0", (void *)GetLensDrawn);
+	engine->RegisterScriptFunction("LensDistort::SetOffsetClamp^1", (void *)SetLensOffsetClamp);
+	engine->RegisterScriptFunction("LensDistort::GetOffsetClamp^0", (void *)GetLensOffsetClamp);
+	engine->RegisterScriptFunction("LensDistort::GetLevel^0", (void *)GetLensLevel);
+	engine->RegisterScriptFunction("LensDistort::SetLevel^1", (void *)GetLensLevel);
+	engine->RegisterScriptFunction("LensDistort::Initialize^6", (void *)LensInitialize);
+
+	engine->RegisterScriptFunction("Translucence::CreateOverlay^8", (void *)CreateTranslucentOverlay);
+	engine->RegisterScriptFunction("Translucence::DeleteOverlay^1", (void *)DeleteTranslucentOverlay);
+	engine->RegisterScriptFunction("Translucence::Move^3", (void *)MoveTranslucentOverlay);
+	engine->RegisterScriptFunction("Translucence::GetOverlayX^1", (void *)GetTranslucentOverlayX);
+	engine->RegisterScriptFunction("Translucence::GetOverlayY^1", (void *)GetTranslucentOverlayY);
+	engine->RegisterScriptFunction("Translucence::GetOverlaySprite^1", (void *)GetTranslucentOverlaySprite);
+	engine->RegisterScriptFunction("Translucence::GetOverlayLevel^1", (void *)GetTranslucentOverlayLevel);
+	engine->RegisterScriptFunction("Translucence::GetOverlayEnabled^1", (void *)GetTranslucentOverlayEnabled);
+	engine->RegisterScriptFunction("Translucence::GetOverlayAlpha^1", (void *)GetTranslucentOverlayAlpha);
+	engine->RegisterScriptFunction("Translucence::SetOverlayAlpha^2", (void *)SetTranslucentOverlayAlpha);
+	engine->RegisterScriptFunction("Translucence::SetOverlayEnabled^2", (void *)SetTranslucentOverlayEnabled);
+	engine->RegisterScriptFunction("Translucence::DrawTransSprite^6", (void *)DrawTransSprite);
+
+	engine->RegisterScriptFunction("Starfield::GetOverscan^0", (void *)GetStarfieldOverscan);
+	engine->RegisterScriptFunction("Starfield::SetOverscan^1", (void *)SetStarfieldOverscan);
+	engine->RegisterScriptFunction("Starfield::GetOriginX^0", (void *)GetStarfieldOriginX);
+	engine->RegisterScriptFunction("Starfield::GetOriginY^0", (void *)GetStarfieldOriginY);
+	engine->RegisterScriptFunction("Starfield::SetDepthMultiplier^1", (void *)SetStarfieldDepthMultiplier);
+	engine->RegisterScriptFunction("Starfield::GetDepthMultiplier^0", (void *)GetStarfieldDepthMultiplier);
+	engine->RegisterScriptFunction("Starfield::GetMaxStars^0", (void *)GetStarfieldMaxStars);
+	engine->RegisterScriptFunction("Starfield::SetStarSpriteScaleBoost^1", (void *)SetStarSpriteScaleBoost);
+	engine->RegisterScriptFunction("Starfield::GetStarSpriteScaleBoost^0", (void *)GetStarSpriteScaleBoost);
+	engine->RegisterScriptFunction("Starfield::SetStarMaxRadius^2", (void *)SetStarMaxRadius);
+	engine->RegisterScriptFunction("Starfield::GetStarMaxRadius^0", (void *)GetStarMaxRadius);
+	engine->RegisterScriptFunction("Starfield::GetStarX^1", (void *)GetStarX);
+	engine->RegisterScriptFunction("Starfield::GetStarY^1", (void *)GetStarY);
+	engine->RegisterScriptFunction("Starfield::GetStarZ^1", (void *)GetStarZ);
+	engine->RegisterScriptFunction("Starfield::SetStarPosition^4", (void *)SetStarPosition);
+	engine->RegisterScriptFunction("Starfield::RotateStar^4", (void *)RotateStar);
+	engine->RegisterScriptFunction("Starfield::SetStarColor^2", (void *)SetStarColor);
+	engine->RegisterScriptFunction("Starfield::GetStarColor^1", (void *)GetStarColor);
+	engine->RegisterScriptFunction("Starfield::SetStarSprite^2", (void *)SetStarSprite);
+	engine->RegisterScriptFunction("Starfield::GetStarSprite^1", (void *)GetStarSprite);
+	engine->RegisterScriptFunction("Starfield::SetStarSpriteRange^3", (void *)SetStarSpriteRange);
+	engine->RegisterScriptFunction("Starfield::Initialize^2", (void *)InitializeStars);
+	engine->RegisterScriptFunction("Starfield::Iterate^1", (void *)IterateStars);
+	engine->RegisterScriptFunction("Starfield::Draw^2", (void *)DrawStars);
+	engine->RegisterScriptFunction("Starfield::SetOriginPoint^2", (void *)SetStarsOriginPoint);
+
+	engine->RegisterScriptFunction("Plasma::DoFire^8", (void *)DoFire);
+	engine->RegisterScriptFunction("Plasma::SetPlasmaType^5", (void *)SetPlasmaType);
+	engine->RegisterScriptFunction("Plasma::ResetPlasmaSettings^0", (void *)ResetPlasmaSettings);
+	engine->RegisterScriptFunction("Plasma::DrawPlasma^3", (void *)DrawPlasma);
+	engine->RegisterScriptFunction("Plasma::SetRootType^1", (void *)SetPlasmaRootType);
+	engine->RegisterScriptFunction("Plasma::GetRootType^0", (void *)GetPlasmaRootType);
+
+	engine->RegisterScriptFunction("Reflections::Set^1", (void *)SetReflections);
+	engine->RegisterScriptFunction("Reflections::IsReflecting^0", (void *)IsReflectionsOn);
+	engine->RegisterScriptFunction("Reflections::SetCharacterReflected^2", (void *)SetCharacterReflected);
+	engine->RegisterScriptFunction("Reflections::GetCharacterReflected^1", (void *)GetCharacterReflected);
+	engine->RegisterScriptFunction("Reflections::SetObjectReflected^2", (void *)SetObjectReflected);
+	engine->RegisterScriptFunction("Reflections::GetObjectReflected^1", (void *)GetObjectReflected);
+	engine->RegisterScriptFunction("Reflections::ReplaceCharacterReflectionView^2", (void *)ReplaceCharacterReflectionView);
+	engine->RegisterScriptFunction("Reflections::SetObjectReflectionIgnoreScaling^2", (void *)SetObjectReflectionIgnoreScaling);
+	engine->RequestEventHook(AGSE_PRESCREENDRAW);
+	engine->RequestEventHook(AGSE_PREGUIDRAW);
+	engine->RequestEventHook(AGSE_POSTSCREENDRAW);
+	engine->RequestEventHook(AGSE_SAVEGAME);
+	engine->RequestEventHook(AGSE_RESTOREGAME);
+	engine->RequestEventHook(AGSE_ENTERROOM);
+	stars = new starstype [MAX_STARS];
+	Starfield.maxstars = MAX_STARS;
+	Starfield.depthmultiplier = 256;
+	Starfield.speed = 0.5;
+	Starfield.originx = 160;
+	Starfield.originy = 100;
+	Reflection.Characters = new charrefopt [engine->GetNumCharacters()]();
+	lens = new LensDistort [LENS_WIDTH * LENS_WIDTH]();
+	//PreMultiply_Alphas ();
+	plasmaroottype = 0;
+	Make_Sin_Lut();
+	Init_Raycaster();
+}
+
+void AGSPalRender::AGS_EngineShutdown() {
+	// no work to do here - but if we had created any dynamic sprites,
+	// we should delete them here
+	delete[] Reflection.Characters;
+	delete[] Reflection.Objects;
+	//QuitCleanup();
+}
+
+int64 AGSPalRender::AGS_EngineOnEvent(int event, NumberPtr data) {
+	if (event == AGSE_PRESCREENDRAW && clutslot > 0) {
+		if (drawreflections) {
+			int32 sh, sw = 0;
+			engine->GetScreenDimensions(&sw, &sh, nullptr);
+			reflectionmap = new long[sw * sh]();
+			rcolormap = engine->CreateBlankBitmap(sw, sh, 8);
+			ralphamap = engine->CreateBlankBitmap(sw, sh, 8);
+			for (int i = 0; i < engine->GetNumCharacters(); i++) {
+				if (Reflection.Characters[i].reflect == 0) continue;
+				AGSCharacter *tempchar = engine->GetCharacter(i);
+				if (tempchar->room != engine->GetCurrentRoom()) continue;  //if character isn't even in the room, go to next iteration.
+				int32 vx = tempchar->x;
+				int32 vy = tempchar->y;
+				engine->RoomToViewport(&vx, &vy);
+				AGSViewFrame *vf = engine->GetViewFrame(tempchar->view + 1, tempchar->loop, tempchar->frame);
+				int w = engine->GetSpriteWidth(vf->pic);
+				int h = engine->GetSpriteHeight(vf->pic);
+				vx = vx - (w / 2);
+				int32 vxmax = vx + w;
+				int32 vymax = vy + h;
+				if (vxmax < 0 || vy > sh || vx > sw || vymax < 0) continue; //if all of the sprite is off screen in any direction, go to next iteration
+				DrawReflections(i, 0);
+			}
+			for (int i = 0; i < engine->GetNumObjects(); i++) {
+				if (Reflection.Objects[i].reflect == 0) continue;
+				AGSObject *tempobj = engine->GetObject(i);
+				if (!tempobj->on) continue;
+				int32 vx = tempobj->x;
+				int32 vy = tempobj->baseline - tempobj->y;
+				engine->RoomToViewport(&vx, &vy);
+				int32 w = engine->GetSpriteWidth(tempobj->num);
+				int32 h = engine->GetSpriteHeight(tempobj->num);
+				int32 vxmax = vx + w;
+				int32 vymax = vy + h;
+				if (vxmax < 0 || vy > sh || vx > sw || vymax < 0) continue; //if all of the sprite is off screen in any direction, go to next iteration
+				DrawReflections(i, 1);
+			}
+			BITMAP *virtsc = engine->GetVirtualScreen();
+			uint8 *screenbuffer = engine->GetRawBitmapSurface(virtsc);
+			uint8 *colorbuffer = engine->GetRawBitmapSurface(rcolormap);
+			uint8 *alphabuffer = engine->GetRawBitmapSurface(ralphamap);
+			int screenPitch = engine->GetBitmapPitch(virtsc);
+			int colorPitch = engine->GetBitmapPitch(rcolormap);
+			int alphaPitch = engine->GetBitmapPitch(ralphamap);
+			for (int y = 0, screeny = 0, colory = 0, alphay = 0; y < sh; y++, screeny += screenPitch, colory += colorPitch, alphay += alphaPitch)
+				for (int x = 0; x < sw; x++)
+					screenbuffer[screeny+x] = Mix::MixColorAlpha(colorbuffer[colory+x], screenbuffer[screeny+x], alphabuffer[alphay+x]);
+			engine->ReleaseBitmapSurface(rcolormap);
+			engine->ReleaseBitmapSurface(ralphamap);
+			engine->ReleaseBitmapSurface(virtsc);
+			engine->FreeBitmap(rcolormap);
+			engine->FreeBitmap(ralphamap);
+			delete [] reflectionmap;
+		}
+		int i = 0;
+		if (LensOption.draw == 1 && LensOption.level == 0) DrawLens(LensOption.x, LensOption.y);
+		while (i < MAX_OVERLAYS) {
+			if (overlay[i].enabled && overlay[i].level == 0) {
+				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
+			}
+			i++;
+		}
+		if (LensOption.draw == 1 && LensOption.level == 1) DrawLens(LensOption.x, LensOption.y);
+	}
+	if (event == AGSE_PREGUIDRAW && clutslot > 0) {
+		int i = 0;
+		if (LensOption.draw == 1 && LensOption.level == 1) DrawLens(LensOption.x, LensOption.y);
+		while (i < MAX_OVERLAYS) {
+			if (overlay[i].enabled && overlay[i].level == 1) {
+				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
+			}
+			i++;
+		}
+		if (LensOption.draw == 1 && LensOption.level == 2) DrawLens(LensOption.x, LensOption.y);
+	}
+	if (event == AGSE_POSTSCREENDRAW && clutslot > 0) {
+		int i = 0;
+		if (LensOption.draw == 1 && LensOption.level == 3) DrawLens(LensOption.x, LensOption.y);
+		while (i < MAX_OVERLAYS) {
+			if (overlay[i].enabled && overlay[i].level == 2) {
+				DrawTranslucentOverlay(overlay[i].sprite, overlay[i].trans, overlay[i].x, overlay[i].y, overlay[i].spritemask, overlay[i].blendtype);
+			}
+			i++;
+		}
+		if (LensOption.draw == 1 && LensOption.level == 4) DrawLens(LensOption.x, LensOption.y);
+	}
+	if (event == AGSE_SAVEGAME) {
+		Serializer s(engine, data, false);
+		syncGame(s);
+	}
+	if (event == AGSE_RESTOREGAME) {
+		Serializer s(engine, data, true);
+		syncGame(s);
+	}
+	if (event == AGSE_ENTERROOM) {
+		ResetRemapping();
+		delete[] Reflection.Objects;
+		Reflection.Objects = new objrefopt [engine->GetNumObjects()]();
+	}
+	return 0;
+}
+
+void AGSPalRender::syncGame(Serializer &s) {
+	for (int i = 0; i < MAX_OVERLAYS; ++i) {
+		s.syncAsInt(overlay[i].sprite);
+		s.syncAsInt(overlay[i].spritemask);
+		s.syncAsInt(overlay[i].x);
+		s.syncAsInt(overlay[i].y);
+		s.syncAsInt(overlay[i].level);
+		s.syncAsInt(overlay[i].trans);
+		s.syncAsInt(overlay[i].blendtype);
+		s.syncAsBool(overlay[i].enabled);
+	}
+	s.syncAsInt(clutslot);
+	s.syncAsInt(drawreflections);
+
+	for (int j = 0; j < 256; ++j)
+		s.syncAsByte(cycle_remap[j]);
+
+	for (int j = 0; j < 256; ++j) {
+		s.syncAsByte(objectivepal[j].r);
+		s.syncAsByte(objectivepal[j].b);
+		s.syncAsByte(objectivepal[j].g);
+	}
+
+	for (int j = 0; j < 256; ++j) {
+		s.syncAsDouble(sprite[j].x);
+		s.syncAsDouble(sprite[j].y);
+		s.syncAsInt(sprite[j].texture);
+		s.syncAsByte(sprite[j].alpha);
+		s.syncAsDouble(sprite[j].uDivW);
+		s.syncAsDouble(sprite[j].uDivH);
+		s.syncAsDouble(sprite[j].vMove);
+		s.syncAsDouble(sprite[j].hMove);
+		s.syncAsInt8(sprite[j].objectinteract);
+		s.syncAsInt(sprite[j].view);
+		s.syncAsInt(sprite[j].frame);
+		s.syncAsInt(sprite[j].angle);
+	}
+
+	for (int j = 0; j < 256; ++j) {
+		for (int k = 0; k < 4; ++k) {
+			s.syncAsInt(wallData[j].texture[k]);
+			s.syncAsInt(wallData[j].solid[k]);
+			s.syncAsInt(wallData[j].ignorelighting[k]);
+			s.syncAsInt(wallData[j].alpha[k]);
+			s.syncAsInt(wallData[j].blendtype[k]);
+			s.syncAsInt(wallData[j].mask[k]);
+		}
+
+		s.syncAsByte(wallData[j].hotspotinteract);
+	}
+
+	s.syncAsBool(raycastOn);
+	s.syncAsBool(heightmapOn);
+	s.syncAsDouble(posX);
+	s.syncAsDouble(posY);
+	s.syncAsDouble(dirX);
+	s.syncAsDouble(dirY);
+	s.syncAsDouble(planeX);
+	s.syncAsDouble(planeY);
+	s.syncAsDouble(moveSpeed);
+	s.syncAsDouble(rotSpeed);
+
+	if (raycastOn) { //If the raycaster is active, we have additional data to save.
+		for (int i = 0; i < MAP_WIDTH; ++i)
+			for (int j = 0; j < MAP_HEIGHT; ++j) {
+				s.syncAsByte(worldMap[i][j]);
+				s.syncAsByte(lightMap[i][j]);
+				s.syncAsInt(ceilingMap[i][j]);
+				s.syncAsInt(floorMap[i][j]);
+				s.syncAsInt(heightMap[i][j]);
+			}
+	}
+
+	s.syncAsInt(textureSlot);
+	if (s.isLoading() && textureSlot)
+		MakeTextures(textureSlot);
+
+	s.syncAsInt(skybox);
+	s.syncAsInt(ambientlight);
+
+	if (s.isLoading())
+		LoadCLUT(clutslot);
+}
+
+} // namespace AGSPalRender
+} // namespace Plugins
+} // namespace AGS3
diff --git a/engines/ags/plugins/ags_pal_render/pal_render.h b/engines/ags/plugins/ags_pal_render/pal_render.h
index aac0469da3..edc5f18ab9 100644
--- a/engines/ags/plugins/ags_pal_render/pal_render.h
+++ b/engines/ags/plugins/ags_pal_render/pal_render.h
@@ -1,193 +1,193 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or(at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef AGS_PLUGINS_AGS_PAL_RENDER_PAL_RENDER_H
-#define AGS_PLUGINS_AGS_PAL_RENDER_PAL_RENDER_H
-
-#include "ags/lib/allegro.h"
-#include "ags/plugins/agsplugin.h"
-#include "common/algorithm.h"
-
-namespace AGS3 {
-namespace Plugins {
-namespace AGSPalRender {
-
-#define SCRIPT_FLOAT(x) int32 __script_float##x
-#define INIT_SCRIPT_FLOAT(x) float x; memcpy(&x, &__script_float##x, sizeof(float))
-#define FLOAT_RETURN_TYPE int32
-#define RETURN_FLOAT(x) int32 __ret##x; memcpy(&__ret##x, &x, sizeof(float)); return __ret##x
-
-struct PALSTRUCT {
-	byte r;
-	byte b;
-	byte g;
-};
-
-extern IAGSEngine *engine;
-extern unsigned char clut[65536];
-extern unsigned char cycle_remap [256];
-extern const int alphamultiply [4096];
-extern PALSTRUCT objectivepal[256];
-
-// this class exists solely to take advantage of g++'s
-// -fvisibility-inlines-hidden option, so that these
-// methods can be inlined without any trace or complaint
-class Mix {
-public:
-//unsigned char MixColorAlpha (unsigned char fg,unsigned char bg,unsigned char alpha);
-//unsigned char MixColorAdditive (unsigned char fg,unsigned char bg,unsigned char alpha);
-	static unsigned char MixColorAlpha(unsigned char fg, unsigned char bg, unsigned char alpha, int use_objpal = 0) {
-		unsigned char rfg = cycle_remap[fg]; //Automatic remapping of palette slots.
-		//unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
-		AGSColor *palette = engine->GetPalette();
-		int i = 0;
-		//int out_r = (palette[fg].r>>1) * alpha + (palette[bg].r>>1) * (255 - alpha);
-		//int out_g = palette[fg].g * alpha + palette[bg].g * (255 - alpha);
-		//int out_b = (palette[fg].b>>1) * alpha + (palette[bg].b>>1) * (255 - alpha);
-		int out_r, out_g, out_b;
-		if (use_objpal == 0) {
-			out_r = (objectivepal[rfg].r >> 1) *alpha + (palette[bg].r >> 1) *(255 - alpha);
-			out_g = objectivepal[rfg].g * alpha + palette[bg].g * (255 - alpha);
-			out_b = (objectivepal[rfg].b >> 1) *alpha + (palette[bg].b >> 1) *(255 - alpha);
-		} else {
-			out_r = (objectivepal[rfg].r >> 1) *alpha + (objectivepal[bg].r >> 1) *(255 - alpha);
-			out_g = objectivepal[rfg].g * alpha + objectivepal[bg].g * (255 - alpha);
-			out_b = (objectivepal[rfg].b >> 1) *alpha + (objectivepal[bg].b >> 1) *(255 - alpha);
-		}
-		//char ralpha = MAX(0,MIN(63,alpha>>2));
-		//unsigned char invralpha = 64-ralpha;
-		//if (ralpha > alpha) engine->AbortGame ("wtf");
-		//int out_r = alphamultiply[((palette[fg].r>>1)<<6) +ralpha] + alphamultiply[((palette[bg].r>>1)<<6) +(invralpha)];
-		//int out_g = alphamultiply[((palette[fg].g)   <<6) +ralpha] + alphamultiply[((palette[bg].g)   <<6) +(invralpha)];
-		//int out_b = alphamultiply[((palette[fg].b>>1)<<6) +ralpha] + alphamultiply[((palette[bg].b>>1)<<6) +(invralpha)];
-		out_r = (out_r + 1 + (out_r >> 8)) >> 8;
-		out_g = (out_g + 1 + (out_g >> 8)) >> 8;
-		out_b = (out_b + 1 + (out_b >> 8)) >> 8;
-		//out_r = (out_r + 1 + (out_r >> 6)) >> 6;
-		//out_g = (out_g + 1 + (out_g >> 6)) >> 6;
-		//out_b = (out_b + 1 + (out_b >> 6)) >> 6;
-		i = ((out_r << 11) | (out_g << 5) | out_b);
-		unsigned char *clutp = clut;
-		//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
-		return cycle_remap[*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
-		//engine->ReleaseBitmapSurface (clutspr);
-	}
-
-	static unsigned char MixColorLightLevel(unsigned char fg, unsigned char intensity) {
-		unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
-		int i = 0;
-		//int dark_r = (((palette[fg].r>>1) * (intensity))>>8);
-		//int dark_b = (((palette[fg].b>>1) * (intensity))>>8);
-		//int dark_g = (((palette[fg].g)    * (intensity))>>8);
-		int dark_r = (((objectivepal[rfg].r >> 1) * (intensity)) >> 8);
-		int dark_b = (((objectivepal[rfg].b >> 1) * (intensity)) >> 8);
-		int dark_g = (((objectivepal[rfg].g)    * (intensity)) >> 8);
-		i = ((dark_r << 11) | (dark_g << 5) | dark_b);
-		unsigned char *clutp = clut;
-		return cycle_remap [*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
-	}
-
-	static unsigned char MixColorAdditive(unsigned char fg, unsigned char bg, unsigned char alpha, int use_objpal = 0) {
-		unsigned char rfg = cycle_remap[fg]; //Automatic remapping of palette slots.
-		//unsigned char rbg = cycle_remap[bg]; //Saves on typing elsewhere.
-		//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
-		//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
-		//unsigned char **clutarray = engine->GetRawBitmapSurface (clutspr);
-		AGSColor *palette = engine->GetPalette();
-		int i = 0;
-		int add_r, add_b, add_g = 0;
-		//char ralpha = MAX(0,MIN(63,alpha>>2));
-		//add_r = (((palette[fg].r>>1) * (alpha))>>8);
-		//add_b = (((palette[fg].b>>1) * (alpha))>>8);
-		//add_g = (((palette[fg].g)    * (alpha))>>8);
-		add_r = (((objectivepal[rfg].r >> 1) * (alpha)) >> 8);
-		add_b = (((objectivepal[rfg].b >> 1) * (alpha)) >> 8);
-		add_g = (((objectivepal[rfg].g)    * (alpha)) >> 8);
-		//int a_g = MAX(0,MIN(63,alpha>>2));
-		//add_r = ((alphamultiply[(palette[fg].r>>1)<<6)+ralpha])>>6);
-		//add_b = ((alphamultiply[(palette[fg].b>>1)<<6)+ralpha])>>6);
-		//add_g = ((alphamultiply[(palette[fg].g)   <<6)+ralpha])>>6);
-		//int out_r = MIN(31,(palette[bg].r>>1) + add_r);
-		//int out_g = MIN(63, palette[bg].g     + add_g);
-		//int out_b = MIN(31,(palette[bg].b>>1) + add_b);
-		int out_r, out_g, out_b;
-		if (use_objpal == 0) {
-			out_r = MIN(31, (palette[bg].r >> 1) + add_r);
-			out_g = MIN(63, palette[bg].g     + add_g);
-			out_b = MIN(31, (palette[bg].b >> 1) + add_b);
-		} else {
-			out_r = MIN(31, (objectivepal [bg].r >> 1) + add_r);
-			out_g = MIN(63, objectivepal [bg].g     + add_g);
-			out_b = MIN(31, (objectivepal [bg].b >> 1) + add_b);
-		}
-		i = ((out_r << 11) | (out_g << 5) | out_b);
-		unsigned char *clutp = clut;
-		unsigned char result = cycle_remap [*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
-		//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
-		//engine->ReleaseBitmapSurface (clutspr);
-		return result;
-	}
-
-	static unsigned char MixColorMultiply(unsigned char fg, unsigned char bg, unsigned char alpha, int use_objpal = 0) {
-		unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
-		unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
-		AGSColor *palette = engine->GetPalette();
-		int i = 0;
-		int mul_r, mul_b, mul_g = 0;
-		int out_r, out_g, out_b = 0;
-		if (use_objpal == 0) {
-			mul_r = ((objectivepal[rfg].r >> 1) * (palette[rbg].r >> 1)) / 64;
-			mul_b = ((objectivepal[rfg].b >> 1) * (palette[rbg].b >> 1)) / 64;
-			mul_g = ((objectivepal[rfg].g * palette[rbg].g) / 64);
-			out_r = ((palette[rbg].r >> 1) * (63 - (alpha / 4)) + (mul_r * (alpha / 4))) / 63;
-			out_g = (palette[rbg].g * (63 - (alpha / 4)) + (mul_g * (alpha / 4))) / 63;
-			out_b = ((palette[rbg].b >> 1) * (63 - (alpha / 4)) + (mul_b * (alpha / 4))) / 63;
-		} else {
-			mul_r = ((objectivepal[rfg].r >> 1) * (objectivepal[rbg].r >> 1)) / 64;
-			mul_b = ((objectivepal[rfg].b >> 1) * (objectivepal[rbg].b >> 1)) / 64;
-			mul_g = ((objectivepal[rfg].g * objectivepal[rbg].g) / 64);
-
-			out_r = ((objectivepal[rbg].r >> 1) * (63 - (alpha / 4)) + (mul_r * (alpha / 4))) / 63;
-			out_g = (objectivepal[rbg].g * (63 - (alpha / 4)) + (mul_g * (alpha / 4))) / 63;
-			out_b = ((objectivepal[rbg].b >> 1) * (63 - (alpha / 4)) + (mul_b * (alpha / 4))) / 63;
-		}
-		i = ((out_r << 11) | (out_g << 5) | out_b);
-		unsigned char *clutp = clut;
-		unsigned char result = cycle_remap [*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
-		//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
-		//engine->ReleaseBitmapSurface (clutspr);
-		return result;
-	}
-
-};
-
-unsigned char GetColor565(unsigned char r, unsigned char g, unsigned char b);
-
-unsigned short root(unsigned short x);
-float FastSin(float x);
-float FastCos(float x);
-
-} // namespace AGSPalRender
-} // namespace Plugins
-} // namespace AGS3
-
-#endif
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef AGS_PLUGINS_AGS_PAL_RENDER_PAL_RENDER_H
+#define AGS_PLUGINS_AGS_PAL_RENDER_PAL_RENDER_H
+
+#include "ags/lib/allegro.h"
+#include "ags/plugins/agsplugin.h"
+#include "common/algorithm.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSPalRender {
+
+#define SCRIPT_FLOAT(x) int32 __script_float##x
+#define INIT_SCRIPT_FLOAT(x) float x; memcpy(&x, &__script_float##x, sizeof(float))
+#define FLOAT_RETURN_TYPE int32
+#define RETURN_FLOAT(x) int32 __ret##x; memcpy(&__ret##x, &x, sizeof(float)); return __ret##x
+
+struct PALSTRUCT {
+	byte r;
+	byte b;
+	byte g;
+};
+
+extern IAGSEngine *engine;
+extern unsigned char clut[65536];
+extern unsigned char cycle_remap [256];
+extern const int alphamultiply [4096];
+extern PALSTRUCT objectivepal[256];
+
+// this class exists solely to take advantage of g++'s
+// -fvisibility-inlines-hidden option, so that these
+// methods can be inlined without any trace or complaint
+class Mix {
+public:
+//unsigned char MixColorAlpha (unsigned char fg,unsigned char bg,unsigned char alpha);
+//unsigned char MixColorAdditive (unsigned char fg,unsigned char bg,unsigned char alpha);
+	static unsigned char MixColorAlpha(unsigned char fg, unsigned char bg, unsigned char alpha, int use_objpal = 0) {
+		unsigned char rfg = cycle_remap[fg]; //Automatic remapping of palette slots.
+		//unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
+		AGSColor *palette = engine->GetPalette();
+		int i = 0;
+		//int out_r = (palette[fg].r>>1) * alpha + (palette[bg].r>>1) * (255 - alpha);
+		//int out_g = palette[fg].g * alpha + palette[bg].g * (255 - alpha);
+		//int out_b = (palette[fg].b>>1) * alpha + (palette[bg].b>>1) * (255 - alpha);
+		int out_r, out_g, out_b;
+		if (use_objpal == 0) {
+			out_r = (objectivepal[rfg].r >> 1) *alpha + (palette[bg].r >> 1) *(255 - alpha);
+			out_g = objectivepal[rfg].g * alpha + palette[bg].g * (255 - alpha);
+			out_b = (objectivepal[rfg].b >> 1) *alpha + (palette[bg].b >> 1) *(255 - alpha);
+		} else {
+			out_r = (objectivepal[rfg].r >> 1) *alpha + (objectivepal[bg].r >> 1) *(255 - alpha);
+			out_g = objectivepal[rfg].g * alpha + objectivepal[bg].g * (255 - alpha);
+			out_b = (objectivepal[rfg].b >> 1) *alpha + (objectivepal[bg].b >> 1) *(255 - alpha);
+		}
+		//char ralpha = MAX(0,MIN(63,alpha>>2));
+		//unsigned char invralpha = 64-ralpha;
+		//if (ralpha > alpha) engine->AbortGame ("wtf");
+		//int out_r = alphamultiply[((palette[fg].r>>1)<<6) +ralpha] + alphamultiply[((palette[bg].r>>1)<<6) +(invralpha)];
+		//int out_g = alphamultiply[((palette[fg].g)   <<6) +ralpha] + alphamultiply[((palette[bg].g)   <<6) +(invralpha)];
+		//int out_b = alphamultiply[((palette[fg].b>>1)<<6) +ralpha] + alphamultiply[((palette[bg].b>>1)<<6) +(invralpha)];
+		out_r = (out_r + 1 + (out_r >> 8)) >> 8;
+		out_g = (out_g + 1 + (out_g >> 8)) >> 8;
+		out_b = (out_b + 1 + (out_b >> 8)) >> 8;
+		//out_r = (out_r + 1 + (out_r >> 6)) >> 6;
+		//out_g = (out_g + 1 + (out_g >> 6)) >> 6;
+		//out_b = (out_b + 1 + (out_b >> 6)) >> 6;
+		i = ((out_r << 11) | (out_g << 5) | out_b);
+		unsigned char *clutp = clut;
+		//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
+		return cycle_remap[*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
+		//engine->ReleaseBitmapSurface (clutspr);
+	}
+
+	static unsigned char MixColorLightLevel(unsigned char fg, unsigned char intensity) {
+		unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
+		int i = 0;
+		//int dark_r = (((palette[fg].r>>1) * (intensity))>>8);
+		//int dark_b = (((palette[fg].b>>1) * (intensity))>>8);
+		//int dark_g = (((palette[fg].g)    * (intensity))>>8);
+		int dark_r = (((objectivepal[rfg].r >> 1) * (intensity)) >> 8);
+		int dark_b = (((objectivepal[rfg].b >> 1) * (intensity)) >> 8);
+		int dark_g = (((objectivepal[rfg].g)    * (intensity)) >> 8);
+		i = ((dark_r << 11) | (dark_g << 5) | dark_b);
+		unsigned char *clutp = clut;
+		return cycle_remap [*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
+	}
+
+	static unsigned char MixColorAdditive(unsigned char fg, unsigned char bg, unsigned char alpha, int use_objpal = 0) {
+		unsigned char rfg = cycle_remap[fg]; //Automatic remapping of palette slots.
+		//unsigned char rbg = cycle_remap[bg]; //Saves on typing elsewhere.
+		//BITMAP *clutspr = engine->GetSpriteGraphic (clutslot);
+		//if (!clutspr) engine->AbortGame ("MixColorAlpha: Can't load CLUT sprite into memory.");
+		//uint8 *clutarray = engine->GetRawBitmapSurface (clutspr);
+		AGSColor *palette = engine->GetPalette();
+		int i = 0;
+		int add_r, add_b, add_g = 0;
+		//char ralpha = MAX(0,MIN(63,alpha>>2));
+		//add_r = (((palette[fg].r>>1) * (alpha))>>8);
+		//add_b = (((palette[fg].b>>1) * (alpha))>>8);
+		//add_g = (((palette[fg].g)    * (alpha))>>8);
+		add_r = (((objectivepal[rfg].r >> 1) * (alpha)) >> 8);
+		add_b = (((objectivepal[rfg].b >> 1) * (alpha)) >> 8);
+		add_g = (((objectivepal[rfg].g)    * (alpha)) >> 8);
+		//int a_g = MAX(0,MIN(63,alpha>>2));
+		//add_r = ((alphamultiply[(palette[fg].r>>1)<<6)+ralpha])>>6);
+		//add_b = ((alphamultiply[(palette[fg].b>>1)<<6)+ralpha])>>6);
+		//add_g = ((alphamultiply[(palette[fg].g)   <<6)+ralpha])>>6);
+		//int out_r = MIN(31,(palette[bg].r>>1) + add_r);
+		//int out_g = MIN(63, palette[bg].g     + add_g);
+		//int out_b = MIN(31,(palette[bg].b>>1) + add_b);
+		int out_r, out_g, out_b;
+		if (use_objpal == 0) {
+			out_r = MIN(31, (palette[bg].r >> 1) + add_r);
+			out_g = MIN(63, palette[bg].g     + add_g);
+			out_b = MIN(31, (palette[bg].b >> 1) + add_b);
+		} else {
+			out_r = MIN(31, (objectivepal [bg].r >> 1) + add_r);
+			out_g = MIN(63, objectivepal [bg].g     + add_g);
+			out_b = MIN(31, (objectivepal [bg].b >> 1) + add_b);
+		}
+		i = ((out_r << 11) | (out_g << 5) | out_b);
+		unsigned char *clutp = clut;
+		unsigned char result = cycle_remap [*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
+		//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
+		//engine->ReleaseBitmapSurface (clutspr);
+		return result;
+	}
+
+	static unsigned char MixColorMultiply(unsigned char fg, unsigned char bg, unsigned char alpha, int use_objpal = 0) {
+		unsigned char rfg = cycle_remap [fg]; //Automatic remapping of palette slots.
+		unsigned char rbg = cycle_remap [bg]; //Saves on typing elsewhere.
+		AGSColor *palette = engine->GetPalette();
+		int i = 0;
+		int mul_r, mul_b, mul_g = 0;
+		int out_r, out_g, out_b = 0;
+		if (use_objpal == 0) {
+			mul_r = ((objectivepal[rfg].r >> 1) * (palette[rbg].r >> 1)) / 64;
+			mul_b = ((objectivepal[rfg].b >> 1) * (palette[rbg].b >> 1)) / 64;
+			mul_g = ((objectivepal[rfg].g * palette[rbg].g) / 64);
+			out_r = ((palette[rbg].r >> 1) * (63 - (alpha / 4)) + (mul_r * (alpha / 4))) / 63;
+			out_g = (palette[rbg].g * (63 - (alpha / 4)) + (mul_g * (alpha / 4))) / 63;
+			out_b = ((palette[rbg].b >> 1) * (63 - (alpha / 4)) + (mul_b * (alpha / 4))) / 63;
+		} else {
+			mul_r = ((objectivepal[rfg].r >> 1) * (objectivepal[rbg].r >> 1)) / 64;
+			mul_b = ((objectivepal[rfg].b >> 1) * (objectivepal[rbg].b >> 1)) / 64;
+			mul_g = ((objectivepal[rfg].g * objectivepal[rbg].g) / 64);
+
+			out_r = ((objectivepal[rbg].r >> 1) * (63 - (alpha / 4)) + (mul_r * (alpha / 4))) / 63;
+			out_g = (objectivepal[rbg].g * (63 - (alpha / 4)) + (mul_g * (alpha / 4))) / 63;
+			out_b = ((objectivepal[rbg].b >> 1) * (63 - (alpha / 4)) + (mul_b * (alpha / 4))) / 63;
+		}
+		i = ((out_r << 11) | (out_g << 5) | out_b);
+		unsigned char *clutp = clut;
+		unsigned char result = cycle_remap [*(clutp + i)]; //Once again, to make sure that the palette slot used is the right one.
+		//unsigned char result = cycle_remap [clut[i>>8][i%256]]; //Once again, to make sure that the palette slot used is the right one.
+		//engine->ReleaseBitmapSurface (clutspr);
+		return result;
+	}
+
+};
+
+unsigned char GetColor565(unsigned char r, unsigned char g, unsigned char b);
+
+unsigned short root(unsigned short x);
+float FastSin(float x);
+float FastCos(float x);
+
+} // namespace AGSPalRender
+} // namespace Plugins
+} // namespace AGS3
+
+#endif
diff --git a/engines/ags/plugins/ags_pal_render/raycast.cpp b/engines/ags/plugins/ags_pal_render/raycast.cpp
index 329750babc..d4a104d88c 100644
--- a/engines/ags/plugins/ags_pal_render/raycast.cpp
+++ b/engines/ags/plugins/ags_pal_render/raycast.cpp
@@ -105,19 +105,21 @@ int Ray_GetNoClip() {
 
 void Ray_DrawTile(int spr, int tile) {
 	BITMAP *img = engine->GetSpriteGraphic(spr);
-	unsigned char **sprarray = engine->GetRawBitmapSurface(img);
-	for (int y = 0; y < MAP_HEIGHT; ++y)
+	uint8 *sprarray = engine->GetRawBitmapSurface(img);
+	int pitch = engine->GetBitmapPitch(img);
+	for (int y = 0, yy = 0; y < MAP_HEIGHT; ++y, yy += pitch)
 		for (int x = 0; x < MAP_WIDTH; ++x)
-			sprarray[y][x] = texture [tile][(texWidth * y) + x];
+			sprarray[yy + x] = texture [tile][(texWidth * y) + x];
 	engine->ReleaseBitmapSurface(img);
 }
 
 void Ray_DrawOntoTile(int spr, int tile) {
 	BITMAP *img = engine->GetSpriteGraphic(spr);
-	unsigned char **sprarray = engine->GetRawBitmapSurface(img);
-	for (int y = 0; y < MAP_HEIGHT; ++y)
+	uint8 *sprarray = engine->GetRawBitmapSurface(img);
+	int pitch = engine->GetBitmapPitch(img);
+	for (int y = 0, yy = 0; y < MAP_HEIGHT; ++y, yy += pitch)
 		for (int x = 0; x < MAP_WIDTH; ++x)
-			texture [tile][(texWidth * y) + x] = sprarray [y][x];
+			texture [tile][(texWidth * y) + x] = sprarray [yy + x];
 	engine->ReleaseBitmapSurface(img);
 }
 
@@ -330,11 +332,12 @@ void LoadHeightMap(int heightmapSlot) {
 	if (tempw != MAP_WIDTH || temph != MAP_HEIGHT) engine->AbortGame("LoadHeightMap: Map sizes are mismatched!");
 	BITMAP *heightmapBm = engine->GetSpriteGraphic(heightmapSlot);
 	if (!heightmapBm) engine->AbortGame("LoadHeightMap: Cannot load sprite into memory.");
-	unsigned char **hmArray = engine->GetRawBitmapSurface(heightmapBm);
+	uint8 *hmArray = engine->GetRawBitmapSurface(heightmapBm);
+	int pitch = engine->GetBitmapPitch(heightmapBm);
 
 	for (int i = 0; i < tempw; i++) {
 		for (int j = 0; j < temph; j++) {
-			heightMap[i][j] = hmArray[i][j];
+			heightMap[i][j] = hmArray[i * pitch + j];
 		}
 	}
 	engine->ReleaseBitmapSurface(heightmapBm);
@@ -348,37 +351,45 @@ void LoadMap(int worldmapSlot, int lightmapSlot, int ceilingmapSlot, int floorma
 	BITMAP *lightmapBm = nullptr;
 	BITMAP *floormapBm = nullptr;
 	BITMAP *ceilingmapBm = nullptr;
-	unsigned char **wmArray = nullptr;
-	unsigned char **lmArray = nullptr;
-	unsigned char **fmArray = nullptr;
-	unsigned char **cmArray = nullptr;
+	uint8 *wmArray = nullptr;
+	uint8 *lmArray = nullptr;
+	uint8 *fmArray = nullptr;
+	uint8 *cmArray = nullptr;
+	int wmPitch = 0;
+	int lmPitch = 0;
+	int fmPitch = 0;
+	int cmPitch = 0;
 	worldmapBm = engine->GetSpriteGraphic(worldmapSlot);
 	if (!worldmapBm) engine->AbortGame("LoadMap: Couldn't load worldmap sprite into memory.");
 	wmArray = engine->GetRawBitmapSurface(worldmapBm);
+	wmPitch = engine->GetBitmapPitch(worldmapBm);
 	if (engine->GetSpriteWidth(lightmapSlot) != tempw || engine->GetSpriteHeight(lightmapSlot) != temph) engine->AbortGame("LoadMap: Lightmap has different dimensions to worldmap.");
 	else {
 		lightmapBm = engine->GetSpriteGraphic(lightmapSlot);
 		if (!lightmapBm) engine->AbortGame("LoadMap: Couldn't load lightmap sprite into memory.");
 		lmArray = engine->GetRawBitmapSurface(lightmapBm);
+		lmPitch = engine->GetBitmapPitch(lightmapBm);
 	}
 	if (engine->GetSpriteWidth(ceilingmapSlot) != tempw || engine->GetSpriteHeight(ceilingmapSlot) != temph) engine->AbortGame("LoadMap: Ceilingmap has different dimensions to worldmap.");
 	else {
 		ceilingmapBm = engine->GetSpriteGraphic(ceilingmapSlot);
 		if (!ceilingmapBm) engine->AbortGame("LoadMap: Couldn't load ceilingmap sprite into memory.");
 		cmArray = engine->GetRawBitmapSurface(ceilingmapBm);
+		cmPitch = engine->GetBitmapPitch(ceilingmapBm);
 	}
 	if (engine->GetSpriteWidth(floormapSlot) != tempw || engine->GetSpriteHeight(floormapSlot) != temph) engine->AbortGame("LoadMap: Floormap has different dimensions to worldmap.");
 	else {
 		floormapBm = engine->GetSpriteGraphic(floormapSlot);
 		if (!floormapBm) engine->AbortGame("LoadMap: Couldn't load floormap sprite into memory.");
 		fmArray = engine->GetRawBitmapSurface(floormapBm);
+		fmPitch = engine->GetBitmapPitch(floormapBm);
 	}
 	for (int i = 0; i < tempw; i++) {
 		for (int j = 0; j < temph; j++) {
-			worldMap[i][j] = wmArray[i][j];
-			lightMap[i][j] = lmArray[i][j];
-			floorMap[i][j] = fmArray[i][j];
-			ceilingMap[i][j] = cmArray[i][j];
+			worldMap[i][j] = wmArray[i * wmPitch + j];
+			lightMap[i][j] = lmArray[i * lmPitch + j];
+			floorMap[i][j] = fmArray[i * fmPitch + j];
+			ceilingMap[i][j] = cmArray[i * cmPitch + j];
 			heightMap[i][j] = 0;
 			seenMap[i][j] = 0;
 		}
@@ -523,7 +534,8 @@ void MakeTextures(int slot) {
 	int max = (sourceWidth / texWidth) * (sourceHeight / texHeight);
 	if (max > MAX_TEXTURES) engine->AbortGame("MakeTextures: Source file has too many tiles to load.");
 	BITMAP *texspr = engine->GetSpriteGraphic(slot);
-	unsigned char **texbuffer = engine->GetRawBitmapSurface(texspr);
+	uint8 *texbuffer = engine->GetRawBitmapSurface(texspr);
+	int texPitch = engine->GetBitmapPitch(texspr);
 	int numTilesX = sourceWidth / texWidth;
 	int numTilesY = sourceHeight / texHeight;
 	//int totaltiles = numTilesX * numTilesY;
@@ -531,7 +543,7 @@ void MakeTextures(int slot) {
 		for (int numY = 0; numY < numTilesY; ++numY) {
 			for (int x = 0; x < texWidth; ++x)
 				for (int y = 0; y < texHeight; ++y) {
-					texture[(numY * numTilesX) + numX][(texWidth * y) + x] = texbuffer [y + (texHeight * numY)][x + (texWidth * numX)];
+					texture[(numY * numTilesX) + numX][(texWidth * y) + x] = texbuffer [(y + (texHeight * numY)) * texPitch + x + (texWidth * numX)];
 				}
 		}
 	}
@@ -689,7 +701,8 @@ void Raycast_Render(int slot) {
 		engine->SetVirtualScreen(virtsc);
 	}
 	int transwallcount = 0;
-	unsigned char **buffer = engine->GetRawBitmapSurface(screen);
+	uint8 *buffer = engine->GetRawBitmapSurface(screen);
+	int bufferPitch = engine->GetBitmapPitch(screen);
 	for (int x = 0; x < w; x++) {
 		transslicedrawn [x] = false;
 		for (int y = 0; y < h; y++) {
@@ -892,7 +905,7 @@ void Raycast_Render(int slot) {
 							if (ambientpixels && ambientcolor) color = Mix::MixColorMultiply(ambientcolor, color, ambientcolorAmount, 1);
 							if (!wallData[worldMap[mapX][mapY]].ignorelighting[texside] && wall_light < 255) color = Mix::MixColorLightLevel(color, wall_light);
 							if (wallData[worldMap[mapX][mapY]].alpha[texside] == 255 && wallData[worldMap[mapX][mapY]].mask[texside] == 0) {
-								buffer[y][x] = color;
+								buffer[y * bufferPitch + x] = color;
 								if (ambientpixels) ambientweight++;
 								//SET THE ZBUFFER FOR THE SPRITE CASTING
 								ZBuffer[x][y] = perpWallDist; //perpendicular distance is used
@@ -925,7 +938,7 @@ void Raycast_Render(int slot) {
 						}
 						if ((int)mapX == selectedX && (int)mapY == selectedY) {
 							if (texX == 0 || texX == 63 || texY == 0 || texY == 63) {
-								buffer[y][x] = selectedColor;
+								buffer[y * bufferPitch + x] = selectedColor;
 								ZBuffer [x][y] = perpWallDist;
 							}
 						}
@@ -1052,7 +1065,7 @@ void Raycast_Render(int slot) {
 						for (int ny = raisedfloorstart; ny < y; ny++) {
 							if (ny < h && (ZBuffer[x][ny] > currentDist || ZBuffer[x][ny] == 0)) {
 								ZBuffer[x][ny] = currentDist; //perpendicular distance is used
-								buffer[ny][x] = floorcolor;
+								buffer[ny * bufferPitch + x] = floorcolor;
 								interactionmap [x * S_WIDTH + ny] = 0;
 								editorMap [x][ny] = ((short)mapX) << 16 | ((short)mapY);
 							}
@@ -1100,7 +1113,7 @@ void Raycast_Render(int slot) {
 						for (int ny = raisedfloorstart; ny < y; ny++) {
 							if (ZBuffer[x][ny] > currentDist || ZBuffer[x][ny] == 0) {
 								ZBuffer[x][ny] = currentDist; //perpendicular distance is used
-								buffer[ny][x] = floorcolor;
+								buffer[ny * bufferPitch + x] = floorcolor;
 								interactionmap [x * S_WIDTH + ny] = 0;
 								editorMap [x][ny] = ((short)cmapX) << 16 | ((short)cmapY);
 							}
@@ -1113,13 +1126,13 @@ void Raycast_Render(int slot) {
 				//SET THE ZBUFFER FOR THE SPRITE CASTING
 				if (floorcolor > 0 && (currentDist < ZBuffer[x][y] || ZBuffer[x][y] == 0)) {
 					ZBuffer[x][y] = currentDist; //perpendicular distance is used
-					buffer[y][x] = floorcolor;
+					buffer[y * bufferPitch + x] = floorcolor;
 					editorMap [x][y] = ((short)cmapX) << 16 | ((short)cmapY);
 				} else ZBuffer[x][y] = 9999999999999.0;
 				if (currentDist < ZBuffer[x][h - y] || ZBuffer[x][h - y] == 0) {
 					if (ceilingcolor > 0) {
 						ZBuffer[x][h - y] = currentDist; //perpendicular distance is used
-						buffer[h - y][x] = ceilingcolor;
+						buffer[(h - y) * bufferPitch + x] = ceilingcolor;
 					} else ZBuffer[x][h - y] = 999999999999.0;
 					editorMap [x][h - y] = ((short)cmapX) << 16 | ((short)cmapY);
 				}
@@ -1127,9 +1140,9 @@ void Raycast_Render(int slot) {
 				interactionmap [x * S_WIDTH + (h - y)] = 0;
 				if ((int)cmapX == selectedX && (int)cmapY == selectedY) {
 					if (floorTexX == 0 || floorTexX == 63 || floorTexY == 0 || floorTexY == 63) {
-						buffer[y][x] = selectedColor;
+						buffer[y * bufferPitch + x] = selectedColor;
 						ZBuffer [x][y] = perpWallDist;
-						buffer[h - y][x] = selectedColor;
+						buffer[(h - y) * bufferPitch + x] = selectedColor;
 						ZBuffer [x][h - y] = perpWallDist;
 					}
 				}
@@ -1144,8 +1157,8 @@ void Raycast_Render(int slot) {
 					int transwalloffset = transwalldrawn * h;
 					int color = transcolorbuffer[x][transwalloffset + y];
 					if (color != 0) {
-						if (transwallblendmode[transwalldrawn] == 0) buffer[y][x] = Mix::MixColorAlpha(color, buffer[y][x], transalphabuffer[x][transwalloffset + y]); //paint pixel if it isn't black, black is the invisible color
-						else if (transwallblendmode[transwalldrawn] == 1) buffer[y][x] = Mix::MixColorAdditive(color, buffer[y][x], transalphabuffer[x][transwalloffset + y]);
+						if (transwallblendmode[transwalldrawn] == 0) buffer[y * bufferPitch + x] = Mix::MixColorAlpha(color, buffer[y * bufferPitch + x], transalphabuffer[x][transwalloffset + y]); //paint pixel if it isn't black, black is the invisible color
+						else if (transwallblendmode[transwalldrawn] == 1) buffer[y * bufferPitch + x] = Mix::MixColorAdditive(color, buffer[y * bufferPitch + x], transalphabuffer[x][transwalloffset + y]);
 						//if (ZBuffer[x][y] > transzbuffer[transwalldrawn*h+y]) ZBuffer[x][y] = transzbuffer[transwalldrawn*h+y]; //put the sprite on the zbuffer so we can draw around it.
 					}
 				}
@@ -1218,7 +1231,8 @@ void Raycast_Render(int slot) {
 
 		//parameters for scaling and moving the sprites
 		BITMAP *spritetexbm = engine->GetSpriteGraphic(sprite[spriteOrder[i]].texture);
-		unsigned char **spritetex = engine->GetRawBitmapSurface(spritetexbm);
+		uint8 *spritetex = engine->GetRawBitmapSurface(spritetexbm);
+		int spritetexPitch = engine->GetBitmapPitch(spritetexbm);
 		int sprw = engine->GetSpriteWidth(sprite[spriteOrder[i]].texture);
 		int sprh = engine->GetSpriteHeight(sprite[spriteOrder[i]].texture);
 
@@ -1272,20 +1286,20 @@ void Raycast_Render(int slot) {
 						int texY = ((d * sprh) / spriteHeight) / 256;
 						if (texY >= sprh || texY < 0) continue;
 						//unsigned char color = texture[sprite[spriteOrder[i]].texture][texWidth * texY + texX]; //get current color from the texture
-						unsigned char color = spritetex[texY][texX]; //get current color from the texture
+						unsigned char color = spritetex[texY * spritetexPitch + texX]; //get current color from the texture
 						if (color != 0) {
 							if (sprite[spriteOrder[i]].alpha < 255) {
-								if (sprite[spriteOrder[i]].blendmode == 0) color = Mix::MixColorAlpha(color, buffer[y][stripe], sprite[spriteOrder[i]].alpha);
-								if (sprite[spriteOrder[i]].blendmode == 1) color = Mix::MixColorAdditive(color, buffer[y][stripe], sprite[spriteOrder[i]].alpha);
+								if (sprite[spriteOrder[i]].blendmode == 0) color = Mix::MixColorAlpha(color, buffer[y * bufferPitch + stripe], sprite[spriteOrder[i]].alpha);
+								if (sprite[spriteOrder[i]].blendmode == 1) color = Mix::MixColorAdditive(color, buffer[y * bufferPitch + stripe], sprite[spriteOrder[i]].alpha);
 							}
 							color = Mix::MixColorLightLevel(color, spr_light);
 							if (transzbuffer[stripe][transwalldraw * h + y] < spriteTransformY[i] && transzbuffer[stripe][transwalldraw * h + y] != 0 && transslicedrawn[stripe] && transcolorbuffer[stripe][transwalldraw * h + y] > 0 && transalphabuffer[stripe][transwalldraw * h + y] > 0) {
 								if (transwallblendmode[transwalldraw] == 0) color = Mix::MixColorAlpha(color, transcolorbuffer[stripe][transwalldraw * h + y], transalphabuffer[stripe][transwalldraw * h + y]);
 								else if (transwallblendmode[transwalldraw] == 1) color = Mix::MixColorAdditive(color, transcolorbuffer[stripe][transwalldraw * h + y], transalphabuffer[stripe][transwalldraw * h + y]);
-								buffer[y][stripe] = color;
+								buffer[y * bufferPitch + stripe] = color;
 								ZBuffer[stripe][y] = transzbuffer[stripe][transwalldraw * h + y];
 							} else {
-								buffer[y][stripe] = color; //paint pixel if it isn't black, black is the invisible color
+								buffer[y * bufferPitch + stripe] = color; //paint pixel if it isn't black, black is the invisible color
 								ZBuffer[stripe][y] = spriteTransformY[i]; //put the sprite on the zbuffer so we can draw around it.
 							}
 							interactionmap [stripe * S_WIDTH + y] = sprite[spriteOrder[i]].objectinteract << 8;
diff --git a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
index 3c7f5e7591..a181d2aa28 100644
--- a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
+++ b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
@@ -115,18 +115,16 @@ void SpriteFontRenderer::Draw(BITMAP *src, BITMAP *dest, int destx, int desty, i
 
 	int32 srcWidth, srcHeight, destWidth, destHeight, srcColDepth, destColDepth;
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);  //8bit
-	unsigned short **srcshortbuffer = (unsigned short **)srccharbuffer; //16bit;
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer; //32bit
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
 
-	unsigned char **destcharbuffer = _engine->GetRawBitmapSurface(dest);  //8bit
-	unsigned short **destshortbuffer = (unsigned short **)destcharbuffer; //16bit;
-	unsigned int **destlongbuffer = (unsigned int **)destcharbuffer; //32bit
-
-	int transColor = _engine->GetBitmapTransparentColor(src);
+	uint32 transColor = _engine->GetBitmapTransparentColor(src);
+	int srcPitch = _engine->GetBitmapPitch(src);
+	int destPitch = _engine->GetBitmapPitch(dest);
 
 	_engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, &srcColDepth);
 	_engine->GetBitmapDimensions(dest, &destWidth, &destHeight, &destColDepth);
+	int bpp = destColDepth / 8;
 
 	if (srcy + height > srcHeight || srcx + width > srcWidth || srcx < 0 || srcy < 0) return;
 
@@ -139,32 +137,40 @@ void SpriteFontRenderer::Draw(BITMAP *src, BITMAP *dest, int destx, int desty, i
 
 	int srca, srcr, srcg, srcb, desta, destr, destg, destb, finalr, finalg, finalb, finala, col;
 
-	for (int x = startx; x < width; x ++) {
+	int srcxx = (startx + srcx) * bpp;
+	int destxx = (startx + destx) * bpp;
+	for (int x = startx; x < width; ++x, srcxx += bpp, destxx += bpp) {
 
-		for (int y = starty; y <  height; y ++) {
-			int srcyy = y + srcy;
-			int srcxx = x + srcx;
-			int destyy = y + desty;
-			int destxx = x + destx;
+		int srcyy =  (starty + srcy) * srcPitch;
+		int destyy = (starty + desty) * destPitch;
+		for (int y = starty; y <  height; ++y, srcyy += srcPitch, destyy += destPitch) {
+			uint8 *srcCol = srccharbuffer + srcyy + srcxx;
+			uint8 * destCol = destcharbuffer + destyy + destxx;
 			if (destColDepth == 8) {
-				if (srccharbuffer[srcyy][srcxx] != transColor) destcharbuffer[destyy][destxx] = srccharbuffer[srcyy][srcxx];
+				if (*srcCol != transColor)
+					*destCol = *srcCol;
 			} else if (destColDepth == 16) {
-				if (srcshortbuffer[srcyy][srcxx] != transColor) destshortbuffer[destyy][destxx] = srcshortbuffer[srcyy][srcxx];
+				if (*((uint16*)srcCol) != transColor)
+					*((uint16*)destCol) = *((uint16*)srcCol);
 			} else if (destColDepth == 32) {
-				//if (srclongbuffer[srcyy][srcxx] != transColor) destlongbuffer[destyy][destxx] = srclongbuffer[srcyy][srcxx];
+				//if (*((uint32*)srcCol) != transColor)
+				//	*((uint32*)destCol) = *((uint32*)srcCol);
+
+				uint32 srcargb = *((uint32*)srcCol);
+				uint32& destargb = *((uint32*)destCol);
 
-				srca = (geta32(srclongbuffer[srcyy][srcxx]));
+				srca = (geta32(srcargb));
 
 				if (srca != 0) {
 
-					srcr =  getr32(srclongbuffer[srcyy][srcxx]);
-					srcg =  getg32(srclongbuffer[srcyy][srcxx]);
-					srcb =  getb32(srclongbuffer[srcyy][srcxx]);
+					srcr =  getr32(srcargb);
+					srcg =  getg32(srcargb);
+					srcb =  getb32(srcargb);
 
-					destr =  getr32(destlongbuffer[destyy][destxx]);
-					destg =  getg32(destlongbuffer[destyy][destxx]);
-					destb =  getb32(destlongbuffer[destyy][destxx]);
-					desta =  geta32(destlongbuffer[destyy][destxx]);
+					destr =  getr32(destargb);
+					destg =  getg32(destargb);
+					destb =  getb32(destargb);
+					desta =  geta32(destargb);
 
 
 					finalr = srcr;
@@ -177,7 +183,7 @@ void SpriteFontRenderer::Draw(BITMAP *src, BITMAP *dest, int destx, int desty, i
 					finalg = srca * finalg / finala + desta * destg * (255 - srca) / finala / 255;
 					finalb = srca * finalb / finala + desta * destb * (255 - srca) / finala / 255;
 					col = makeacol32(finalr, finalg, finalb, finala);
-					destlongbuffer[destyy][destxx] = col;
+					destargb = col;
 				}
 
 			}
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
index d333fed2e8..01a298426f 100644
--- a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
@@ -126,19 +126,18 @@ void VariableWidthSpriteFontRenderer::Draw(BITMAP *src, BITMAP *dest, int destx,
 
 	int32 srcWidth, srcHeight, destWidth, destHeight, srcColDepth, destColDepth;
 
-	unsigned char **srccharbuffer = _engine->GetRawBitmapSurface(src);  //8bit
-	unsigned short **srcshortbuffer = (unsigned short **)srccharbuffer; //16bit;
-	unsigned int **srclongbuffer = (unsigned int **)srccharbuffer; //32bit
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
 
-	unsigned char **destcharbuffer = _engine->GetRawBitmapSurface(dest);  //8bit
-	unsigned short **destshortbuffer = (unsigned short **)destcharbuffer; //16bit;
-	unsigned int **destlongbuffer = (unsigned int **)destcharbuffer; //32bit
-
-	int transColor = _engine->GetBitmapTransparentColor(src);
+	uint32 transColor = _engine->GetBitmapTransparentColor(src);
+	int srcPitch = _engine->GetBitmapPitch(src);
+	int destPitch = _engine->GetBitmapPitch(dest);
 
 	_engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, &srcColDepth);
 	_engine->GetBitmapDimensions(dest, &destWidth, &destHeight, &destColDepth);
 
+	int bpp = destColDepth / 8;
+
 	if (srcy + height > srcHeight || srcx + width > srcWidth || srcx < 0 || srcy < 0) return;
 
 	if (width + destx > destWidth) width = destWidth - destx;
@@ -150,45 +149,51 @@ void VariableWidthSpriteFontRenderer::Draw(BITMAP *src, BITMAP *dest, int destx,
 
 	int srca, srcr, srcg, srcb, desta, destr, destg, destb, finalr, finalg, finalb, finala, col;
 
-	for (int x = startx; x < width; x ++) {
+	int srcxx = (startx + srcx) * bpp;
+	int destxx = (startx + destx) * bpp;
+	for (int x = startx; x < width; ++x, srcxx += bpp, destxx += bpp) {
 
-		for (int y = starty; y <  height; y ++) {
-			int srcyy = y + srcy;
-			int srcxx = x + srcx;
-			int destyy = y + desty;
-			int destxx = x + destx;
+		int srcyy =  (starty + srcy) * srcPitch;
+		int destyy = (starty + desty) * destPitch;
+		for (int y = starty; y <  height; ++y, srcyy += srcPitch, destyy += destPitch) {
+			uint8 *srcCol = srccharbuffer + srcyy + srcxx;
+			uint8 * destCol = destcharbuffer + destyy + destxx;
 			if (destColDepth == 8) {
-				if (srccharbuffer[srcyy][srcxx] != transColor) destcharbuffer[destyy][destxx] = srccharbuffer[srcyy][srcxx];
+				if (*srcCol != transColor)
+					*destCol = *srcCol;
 			} else if (destColDepth == 16) {
-				if (srcshortbuffer[srcyy][srcxx] != transColor) destshortbuffer[destyy][destxx] = srcshortbuffer[srcyy][srcxx];
+				if (*((uint16*)srcCol) != transColor)
+					*((uint16*)destCol) = *((uint16*)srcCol);
 			} else if (destColDepth == 32) {
-				//if (srclongbuffer[srcyy][srcxx] != transColor) destlongbuffer[destyy][destxx] = srclongbuffer[srcyy][srcxx];
+				//if (*((uint32*)srcCol) != transColor)
+				//	*((uint32*)destCol) = *((uint32*)srcCol);
 
-				srca = (geta32(srclongbuffer[srcyy][srcxx]));
+				uint32 srcargb = *((uint32*)srcCol);
+				uint32& destargb = *((uint32*)destCol);
 
-				if (srca != 0) {
+				srca = (geta32(srcargb));
 
-					srcr =  getr32(srclongbuffer[srcyy][srcxx]);
-					srcg =  getg32(srclongbuffer[srcyy][srcxx]);
-					srcb =  getb32(srclongbuffer[srcyy][srcxx]);
+				if (srca != 0) {
 
-					destr =  getr32(destlongbuffer[destyy][destxx]);
-					destg =  getg32(destlongbuffer[destyy][destxx]);
-					destb =  getb32(destlongbuffer[destyy][destxx]);
-					desta =  geta32(destlongbuffer[destyy][destxx]);
+					srcr =  getr32(srcargb);
+					srcg =  getg32(srcargb);
+					srcb =  getb32(srcargb);
 
+					destr =  getr32(destargb);
+					destg =  getg32(destargb);
+					destb =  getb32(destargb);
+					desta =  geta32(destargb);
 
 					finalr = srcr;
 					finalg = srcg;
 					finalb = srcb;
 
-
 					finala = 255 - (255 - srca) * (255 - desta) / 255;
 					finalr = srca * finalr / finala + desta * destr * (255 - srca) / finala / 255;
 					finalg = srca * finalg / finala + desta * destg * (255 - srca) / finala / 255;
 					finalb = srca * finalb / finala + desta * destb * (255 - srca) / finala / 255;
 					col = makeacol32(finalr, finalg, finalb, finala);
-					destlongbuffer[destyy][destxx] = col;
+					destargb = col;
 				}
 
 			}
diff --git a/engines/ags/plugins/agsplugin.cpp b/engines/ags/plugins/agsplugin.cpp
index 47bb836b77..c8fafb2ebd 100644
--- a/engines/ags/plugins/agsplugin.cpp
+++ b/engines/ags/plugins/agsplugin.cpp
@@ -246,7 +246,7 @@ void IAGSEngine::GetScreenDimensions(int32 *width, int32 *height, int32 *coldept
 		coldepth[0] = _GP(scsystem).coldepth;
 }
 
-unsigned char **IAGSEngine::GetRawBitmapSurface(BITMAP *bmp) {
+uint8 *IAGSEngine::GetRawBitmapSurface(BITMAP *bmp) {
 	if (!is_linear_bitmap(bmp))
 		quit("!IAGSEngine::GetRawBitmapSurface: invalid bitmap for access to surface");
 	acquire_bitmap(bmp);
@@ -255,7 +255,11 @@ unsigned char **IAGSEngine::GetRawBitmapSurface(BITMAP *bmp) {
 	if (stage && bmp == stage->GetAllegroBitmap())
 		plugins[this->pluginId].invalidatedRegion = 0;
 
-	return (unsigned char **)bmp->getPixels();
+	return (uint8 *)bmp->getPixels();
+}
+
+int IAGSEngine::GetBitmapPitch(BITMAP *bmp) {
+	return bmp->pitch;
 }
 
 void IAGSEngine::ReleaseBitmapSurface(BITMAP *bmp) {
diff --git a/engines/ags/plugins/agsplugin.h b/engines/ags/plugins/agsplugin.h
index b1efb262e8..ce239fa66f 100644
--- a/engines/ags/plugins/agsplugin.h
+++ b/engines/ags/plugins/agsplugin.h
@@ -363,7 +363,9 @@ public:
 	// get screen dimensions
 	AGSIFUNC(void) GetScreenDimensions(int32 *width, int32 *height, int32 *coldepth);
 	// get screen surface to draw on
-	AGSIFUNC(unsigned char **) GetRawBitmapSurface(BITMAP *);
+	AGSIFUNC(uint8 *) GetRawBitmapSurface(BITMAP *);
+	// get screen surface pitch
+	AGSIFUNC(int) GetBitmapPitch(BITMAP *);
 	// release the surface
 	AGSIFUNC(void) ReleaseBitmapSurface(BITMAP *);
 	// get the current mouse co-ordinates


Commit: 551d03a7b4820981e695c8d85b044b01a8a1fbaa
    https://github.com/scummvm/scummvm/commit/551d03a7b4820981e695c8d85b044b01a8a1fbaa
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2021-03-06T21:21:22Z

Commit Message:
AGS: Plug memory leak in SpriteFont plugin

Changed paths:
    engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
    engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp


diff --git a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
index a181d2aa28..cdce0afeb8 100644
--- a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
+++ b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.cpp
@@ -32,7 +32,11 @@ SpriteFontRenderer::SpriteFontRenderer(IAGSEngine *engine) {
 }
 
 
-SpriteFontRenderer::~SpriteFontRenderer(void) {}
+SpriteFontRenderer::~SpriteFontRenderer(void) {
+	for(int i = 0; i < (int)_fonts.size(); i++)
+		delete _fonts[i];
+	_fonts.clear();
+}
 
 void SpriteFontRenderer::SetSpriteFont(int fontNum, int sprite, int rows, int columns, int charWidth, int charHeight, int charMin, int charMax, bool use32bit) {
 	SpriteFont *font = getFontFor(fontNum);
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
index 01a298426f..c78f2831f5 100644
--- a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
@@ -32,7 +32,11 @@ VariableWidthSpriteFontRenderer::VariableWidthSpriteFontRenderer(IAGSEngine *eng
 }
 
 
-VariableWidthSpriteFontRenderer::~VariableWidthSpriteFontRenderer(void) {}
+VariableWidthSpriteFontRenderer::~VariableWidthSpriteFontRenderer(void) {
+	for(int i = 0; i < (int)_fonts.size(); i++)
+		delete _fonts[i];
+	_fonts.clear();
+}
 
 
 


Commit: 6c117d04dd74bde10af4f18d36971de77fbbc850
    https://github.com/scummvm/scummvm/commit/6c117d04dd74bde10af4f18d36971de77fbbc850
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2021-03-06T21:21:22Z

Commit Message:
AGS: Implement AGSSpriteFont plugin variant from Clifftop Games

This variant is used in the games from Clifftop Games, Kathy Rain
and Whispers of a Machine.

The changes are based on https://github.com/adventuregamestudio/ags/pull/834
The ags fork used for the Kathy Rain can be found at https://github.com/josthas/KrusAGS/

Changed paths:
  A engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.cpp
  A engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.h
  A engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.cpp
  A engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.h
  A engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.cpp
  A engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.h
    engines/ags/module.mk
    engines/ags/plugins/ags_sprite_font/ags_sprite_font.cpp
    engines/ags/plugins/ags_sprite_font/ags_sprite_font.h
    engines/ags/plugins/ags_sprite_font/sprite_font_renderer.h
    engines/ags/plugins/ags_sprite_font/variable_width_font.cpp
    engines/ags/plugins/ags_sprite_font/variable_width_font.h
    engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
    engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.h


diff --git a/engines/ags/module.mk b/engines/ags/module.mk
index f03ea450fa..51a7aae292 100644
--- a/engines/ags/module.mk
+++ b/engines/ags/module.mk
@@ -302,12 +302,15 @@ MODULE_OBJS = \
 	plugins/ags_snow_rain/ags_snow_rain.o \
 	plugins/ags_snow_rain/weather.o \
 	plugins/ags_sprite_font/ags_sprite_font.o \
+	plugins/ags_sprite_font/ags_sprite_font_clifftop.o \
 	plugins/ags_sprite_font/character_entry.o \
 	plugins/ags_sprite_font/color.o \
 	plugins/ags_sprite_font/sprite_font.o \
 	plugins/ags_sprite_font/sprite_font_renderer.o \
+	plugins/ags_sprite_font/sprite_font_renderer_clifftop.o \
 	plugins/ags_sprite_font/variable_width_font.o \
 	plugins/ags_sprite_font/variable_width_sprite_font.o \
+	plugins/ags_sprite_font/variable_width_sprite_font_clifftop.o \
 	plugins/ags_tcp_ip/ags_tcp_ip.o \
 	plugins/ags_wadjet_util/ags_wadjet_util.o
 
diff --git a/engines/ags/plugins/ags_sprite_font/ags_sprite_font.cpp b/engines/ags/plugins/ags_sprite_font/ags_sprite_font.cpp
index 19a74dd7c5..e5c28070f8 100644
--- a/engines/ags/plugins/ags_sprite_font/ags_sprite_font.cpp
+++ b/engines/ags/plugins/ags_sprite_font/ags_sprite_font.cpp
@@ -78,6 +78,8 @@ VariableWidthSpriteFontRenderer *AGSSpriteFont::_vWidthRenderer;
 
 AGSSpriteFont::AGSSpriteFont() : PluginBase() {
 	_engine = nullptr;
+	_fontRenderer = nullptr;
+	_vWidthRenderer = nullptr;
 
 	DLL_METHOD(AGS_GetPluginName);
 	DLL_METHOD(AGS_EngineStartup);
@@ -91,10 +93,14 @@ const char *AGSSpriteFont::AGS_GetPluginName() {
 void AGSSpriteFont::AGS_EngineStartup(IAGSEngine *engine) {
 	_engine = engine;
 
-	_engine->PrintDebugConsole("AGSSpriteFont: Init fixed width renderer");
-	_fontRenderer = new SpriteFontRenderer(engine);
-	_engine->PrintDebugConsole("AGSSpriteFont: Init vari width renderer");
-	_vWidthRenderer = new VariableWidthSpriteFontRenderer(engine);
+	if (_fontRenderer == nullptr) {
+		_engine->PrintDebugConsole("AGSSpriteFont: Init fixed width renderer");
+		_fontRenderer = new SpriteFontRenderer(engine);
+	}
+	if (_vWidthRenderer == nullptr) {
+		_engine->PrintDebugConsole("AGSSpriteFont: Init vari width renderer");
+		_vWidthRenderer = new VariableWidthSpriteFontRenderer(engine);
+	}
 	// Make sure it's got the version with the features we need
 	if (_engine->version < MIN_ENGINE_VERSION)
 		_engine->AbortGame("Plugin needs engine version " STRINGIFY(MIN_ENGINE_VERSION) " or newer.");
diff --git a/engines/ags/plugins/ags_sprite_font/ags_sprite_font.h b/engines/ags/plugins/ags_sprite_font/ags_sprite_font.h
index 7fa8f8e065..20f371b5df 100644
--- a/engines/ags/plugins/ags_sprite_font/ags_sprite_font.h
+++ b/engines/ags/plugins/ags_sprite_font/ags_sprite_font.h
@@ -27,16 +27,21 @@
 #include "ags/plugins/ags_sprite_font/sprite_font_renderer.h"
 #include "ags/plugins/ags_sprite_font/variable_width_sprite_font.h"
 
+namespace AGS3 {
+class IAGSEngine;
+}
+
 namespace AGS3 {
 namespace Plugins {
 namespace AGSSpriteFont {
 
 class AGSSpriteFont : public PluginBase {
-private:
+protected:
 	static IAGSEngine *_engine;
 	static SpriteFontRenderer *_fontRenderer;
 	static VariableWidthSpriteFontRenderer *_vWidthRenderer;
-private:
+
+protected:
 	static const char *AGS_GetPluginName();
 	static void AGS_EngineStartup(IAGSEngine *lpEngine);
 	static void AGS_EngineShutdown();
diff --git a/engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.cpp b/engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.cpp
new file mode 100644
index 0000000000..21eb879b7e
--- /dev/null
+++ b/engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.cpp
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.h"
+#include "ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.h"
+#include "ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSSpriteFont {
+
+AGSSpriteFontClifftopGames::AGSSpriteFontClifftopGames() : AGSSpriteFont() {
+	DLL_METHOD(AGS_EngineStartup);
+}
+
+void AGSSpriteFontClifftopGames::AGS_EngineStartup(IAGSEngine *engine) {
+	// Use custom font renderers
+	// They need to be set before calling AGSSpriteFont::AGS_EngineStartup()
+	engine->PrintDebugConsole("AGSSpriteFont: Init fixed width renderer");
+	_fontRenderer = new SpriteFontRenderer(engine);
+
+	engine->PrintDebugConsole("AGSSpriteFont: Init vari width renderer");
+	_vWidthRenderer = new VariableWidthSpriteFontRendererClifftop(engine);
+
+	AGSSpriteFont::AGS_EngineStartup(engine);
+
+	SCRIPT_METHOD(SetLineHeightAdjust);
+}
+
+void AGSSpriteFontClifftopGames::SetLineHeightAdjust(ScriptMethodParams &params) {
+	PARAMS4(int, fontNum, int, LineHeight, int, SpacingHeight, int, SpacingOverride);
+
+	_vWidthRenderer->SetLineHeightAdjust(fontNum, LineHeight, SpacingHeight, SpacingOverride);
+}
+
+} // namespace AGSSpriteFont
+} // namespace Plugins
+} // namespace AGS3
diff --git a/engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.h b/engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.h
new file mode 100644
index 0000000000..dd2a110dfe
--- /dev/null
+++ b/engines/ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.h
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef AGS_PLUGINS_AGS_SPRITE_FONT_CLIFFTOP_H
+#define AGS_PLUGINS_AGS_SPRITE_FONT_CLIFFTOP_H
+
+#include "ags/plugins/ags_sprite_font/ags_sprite_font.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSSpriteFont {
+
+class AGSSpriteFontClifftopGames : public AGSSpriteFont {
+private:
+	static void AGS_EngineStartup(IAGSEngine *engine);
+
+	static void SetLineHeightAdjust(ScriptMethodParams &params);
+
+public:
+	AGSSpriteFontClifftopGames();
+};
+
+} // namespace AGSSpriteFont
+} // namespace Plugins
+} // namespace AGS3
+
+#endif
+
diff --git a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.h b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.h
index 89be9b1bbf..a62387fb96 100644
--- a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.h
+++ b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer.h
@@ -47,7 +47,7 @@ public:
 	void EnsureTextValidForFont(char *text, int fontNumber) override;
 	void SetSpriteFont(int fontNum, int sprite, int rows, int columns, int charWidth, int charHeight, int charMin, int charMax, bool use32bit);
 
-private:
+protected:
 	SpriteFont *getFontFor(int fontNum);
 	void Draw(BITMAP *src, BITMAP *dest, int destx, int desty, int srcx, int srcy, int width, int height);
 	std::vector<SpriteFont * > _fonts;
diff --git a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.cpp b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.cpp
new file mode 100644
index 0000000000..b63376a41b
--- /dev/null
+++ b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.cpp
@@ -0,0 +1,139 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.h"
+#include "ags/plugins/ags_sprite_font/color.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSSpriteFont {
+
+SpriteFontRendererClifftop::SpriteFontRendererClifftop(IAGSEngine *engine) : SpriteFontRenderer(engine) {
+}
+
+SpriteFontRendererClifftop::~SpriteFontRendererClifftop(void) {
+}
+
+bool SpriteFontRendererClifftop::SupportsExtendedCharacters(int fontNumber) {
+	return true;
+}
+
+void SpriteFontRendererClifftop::RenderText(const char *text, int fontNumber, BITMAP *destination, int x, int y, int colour) {
+	SpriteFont *font = getFontFor(fontNumber);
+
+	for (int i = 0; i < (int)strlen(text); i++) {
+		char c = text[i];
+		c -= font->MinChar;
+		int row = c / font->Columns;
+		int column = c % font->Columns;
+		BITMAP *src = _engine->GetSpriteGraphic(font->SpriteNumber);
+		Draw(src, destination, x + (i * font->CharWidth), y, column * font->CharWidth, row * font->CharHeight, font->CharWidth, font->CharHeight, colour);
+	}
+}
+
+void SpriteFontRendererClifftop::Draw(BITMAP *src, BITMAP *dest, int destx, int desty, int srcx, int srcy, int width, int height, int colour) {
+
+	int32 srcWidth = 0, srcHeight = 0, destWidth = 0, destHeight = 0, srcColDepth = 0, destColDepth = 0;
+
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
+
+	uint32 transColor = _engine->GetBitmapTransparentColor(src);
+	int srcPitch = _engine->GetBitmapPitch(src);
+	int destPitch = _engine->GetBitmapPitch(dest);
+
+	_engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, &srcColDepth);
+	_engine->GetBitmapDimensions(dest, &destWidth, &destHeight, &destColDepth);
+	int bpp = destColDepth / 8;
+
+	if (srcy + height > srcHeight || srcx + width > srcWidth || srcx < 0 || srcy < 0) return;
+
+	if (width + destx > destWidth) width = destWidth - destx;
+	if (height + desty > destHeight) height = destHeight - desty;
+
+	int startx = MAX(0, (-1 * destx));
+	int starty = MAX(0, (-1 * desty));
+
+
+	int srca, srcr, srcg, srcb, desta, destr, destg, destb, finalr, finalg, finalb, finala, col, col_r, col_g, col_b;
+	col_r = getr32(colour);
+	col_g = getg32(colour);
+	col_b = getb32(colour);
+
+	int srcxx = (startx + srcx) * bpp;
+	int destxx = (startx + destx) * bpp;
+	for (int x = startx; x < width; ++x, srcxx += bpp, destxx += bpp) {
+
+		int srcyy =  (starty + srcy) * srcPitch;
+		int destyy = (starty + desty) * destPitch;
+		for (int y = starty; y <  height; ++y, srcyy += srcPitch, destyy += destPitch) {
+			uint8 *srcCol = srccharbuffer + srcyy + srcxx;
+			uint8 * destCol = destcharbuffer + destyy + destxx;
+			if (destColDepth == 8) {
+				if (*srcCol != transColor)
+					*destCol = *srcCol;
+			} else if (destColDepth == 16) {
+				if (*((uint16*)srcCol) != transColor)
+					*((uint16*)destCol) = *((uint16*)srcCol);
+			} else if (destColDepth == 32) {
+				//if (*((uint32*)srcCol) != transColor)
+				//	*((uint32*)destCol) = *((uint32*)srcCol);
+
+				uint32 srcargb = *((uint32*)srcCol);
+				uint32& destargb = *((uint32*)destCol);
+
+				srca = (geta32(srcargb));
+
+				if (srca != 0) {
+
+					srcr =  getr32(srcargb);
+					srcg =  getg32(srcargb);
+					srcb =  getb32(srcargb);
+
+					destr =  getr32(destargb);
+					destg =  getg32(destargb);
+					destb =  getb32(destargb);
+					desta =  geta32(destargb);
+
+					finalr = (col_r * srcr) / 255;
+					finalg = (col_g * srcg) / 255;
+					finalb = (col_b * srcb) / 255;
+
+					finala = 255 - (255 - srca) * (255 - desta) / 255;
+					finalr = srca * col_r / finala + desta * destr * (255 - srca) / finala / 255;
+					finalg = srca * col_g / finala + desta * destg * (255 - srca) / finala / 255;
+					finalb = srca * col_b / finala + desta * destb * (255 - srca) / finala / 255;
+					col = makeacol32(finalr, finalg, finalb, finala);
+					destargb = col;
+				}
+
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+	_engine->ReleaseBitmapSurface(dest);
+}
+
+} // namespace AGSSpriteFont
+} // namespace Plugins
+} // namespace AGS3
diff --git a/engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.h b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.h
new file mode 100644
index 0000000000..1db216099a
--- /dev/null
+++ b/engines/ags/plugins/ags_sprite_font/sprite_font_renderer_clifftop.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef AGS_PLUGINS_AGS_SPRITE_FONT_SPR_FONT_RENDERER_CLIFFTOP_H
+#define AGS_PLUGINS_AGS_SPRITE_FONT_SPR_FONT_RENDERER_CLIFFTOP_H
+
+#include "ags/plugins/ags_sprite_font/sprite_font_renderer.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSSpriteFont {
+
+class SpriteFontRendererClifftop : public SpriteFontRenderer {
+public:
+	SpriteFontRendererClifftop(IAGSEngine *engine);
+	virtual ~SpriteFontRendererClifftop(void);
+
+	bool SupportsExtendedCharacters(int fontNumber) override;
+	void RenderText(const char *text, int fontNumber, BITMAP *destination, int x, int y, int colour) override;
+
+private:
+	void Draw(BITMAP *src, BITMAP *dest, int destx, int desty, int srcx, int srcy, int width, int height, int colour);
+
+};
+
+} // namespace AGSSpriteFont
+} // namespace Plugins
+} // namespace AGS3
+
+
+#endif
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_font.cpp b/engines/ags/plugins/ags_sprite_font/variable_width_font.cpp
index 466fee9084..a2ce7a7300 100644
--- a/engines/ags/plugins/ags_sprite_font/variable_width_font.cpp
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_font.cpp
@@ -30,6 +30,9 @@ VariableWidthFont::VariableWidthFont(void) {
 	Spacing = 0;
 	FontReplaced = 0;
 	SpriteNumber = 0;
+	LineHeightAdjust = 0;
+	LineSpacingAdjust = 0;
+	LineSpacingOverride = 0;
 }
 
 
@@ -43,6 +46,12 @@ void VariableWidthFont::SetGlyph(int character, int x, int y, int width, int hei
 	characters[character].Character = character;
 }
 
+void VariableWidthFont::SetLineHeightAdjust(int LineHeight, int SpacingHeight, int SpacingOverride) {
+	LineHeightAdjust = LineHeight;
+	LineSpacingAdjust = SpacingHeight;
+	LineSpacingOverride = SpacingOverride;
+ }
+
 } // namespace AGSSpriteFont
 } // namespace Plugins
 } // namespace AGS3
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_font.h b/engines/ags/plugins/ags_sprite_font/variable_width_font.h
index 96c1f9e544..c773047163 100644
--- a/engines/ags/plugins/ags_sprite_font/variable_width_font.h
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_font.h
@@ -36,9 +36,13 @@ public:
 	VariableWidthFont(void);
 	~VariableWidthFont(void);
 	void SetGlyph(int character, int x, int y, int width, int height);
+	void SetLineHeightAdjust(int LineHeight, int SpacingHeight, int SpacingOverride);
 	int SpriteNumber;
 	int FontReplaced;
 	int Spacing;
+	int LineHeightAdjust;
+	int LineSpacingAdjust;
+	int LineSpacingOverride;
 	std::map<char, CharacterEntry> characters;
 };
 
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
index c78f2831f5..8a6a8763a1 100644
--- a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.cpp
@@ -74,6 +74,14 @@ void VariableWidthSpriteFontRenderer::SetSpacing(int fontNum, int spacing) {
 
 }
 
+void VariableWidthSpriteFontRenderer::SetLineHeightAdjust(int fontNum, int LineHeight, int SpacingHeight, int SpacingOverride)
+ {
+	VariableWidthFont *font = getFontFor(fontNum);
+	font->LineHeightAdjust = LineHeight;
+	font->LineSpacingAdjust = SpacingHeight;
+	font->LineSpacingOverride = SpacingOverride;
+ }
+
 void VariableWidthSpriteFontRenderer::EnsureTextValidForFont(char *text, int fontNumber) {
 	VariableWidthFont *font = getFontFor(fontNumber);
 	Common::String s(text);
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.h b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.h
index ce64d41a9e..9b4cbac05e 100644
--- a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.h
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font.h
@@ -48,8 +48,9 @@ public:
 	void SetGlyph(int fontNum, int charNum, int x, int y, int width, int height);
 	void SetSprite(int fontNum, int spriteNum);
 	void SetSpacing(int fontNum, int spacing);
+	void SetLineHeightAdjust(int fontNum, int LineHeight, int SpacingHeight, int SpacingOverride);
 
-private:
+protected:
 	IAGSEngine *_engine;
 	std::vector<VariableWidthFont * > _fonts;
 	VariableWidthFont *getFontFor(int fontNum);
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.cpp b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.cpp
new file mode 100644
index 0000000000..d2c0fca99b
--- /dev/null
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.cpp
@@ -0,0 +1,156 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.h"
+#include "ags/plugins/ags_sprite_font/color.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSSpriteFont {
+
+VariableWidthSpriteFontRendererClifftop::VariableWidthSpriteFontRendererClifftop(IAGSEngine *engine) : VariableWidthSpriteFontRenderer(engine) {
+}
+
+VariableWidthSpriteFontRendererClifftop::~VariableWidthSpriteFontRendererClifftop(void) {
+}
+
+int VariableWidthSpriteFontRendererClifftop::GetTextHeight(const char *text, int fontNumber) {
+	VariableWidthFont *font = getFontFor(fontNumber);
+	if(strcmp("<LINE_SPACING>", text) == 0)
+		return font->LineSpacingOverride;
+
+	for(int i = 0; i < (int)strlen(text); i++) {
+		if (font->characters.count(text[i]) > 0) {
+			int height = font->characters[text[i]].Height;
+
+			if(strcmp("ZHwypgfjqhkilIK", text) == 0 || strcmp("ZhypjIHQFb", text) == 0 || strcmp("YpyjIHgMNWQ", text) == 0 || strcmp("BigyjTEXT", text) == 0)
+				height += font->LineSpacingAdjust;
+			else
+				height += font->LineHeightAdjust;
+
+			return height;
+		}
+	}
+	return 0;
+}
+
+void VariableWidthSpriteFontRendererClifftop::RenderText(const char *text, int fontNumber, BITMAP *destination, int x, int y, int colour) {
+	VariableWidthFont *font = getFontFor(fontNumber);
+	int totalWidth = 0;
+	for (int i = 0; i < (int)strlen(text); i++) {
+		char c = text[i];
+
+		BITMAP *src = _engine->GetSpriteGraphic(font->SpriteNumber);
+		Draw(src, destination, x + totalWidth, y, font->characters[c].X, font->characters[c].Y, font->characters[c].Width, font->characters[c].Height, colour);
+		totalWidth += font->characters[c].Width;
+		if (text[i] != ' ') totalWidth += font->Spacing;
+	}
+}
+
+void VariableWidthSpriteFontRendererClifftop::Draw(BITMAP *src, BITMAP *dest, int destx, int desty, int srcx, int srcy, int width, int height, int colour) {
+
+	int32 srcWidth, srcHeight, destWidth, destHeight, srcColDepth, destColDepth;
+
+	uint8 *srccharbuffer = _engine->GetRawBitmapSurface(src);
+	uint8 *destcharbuffer = _engine->GetRawBitmapSurface(dest);
+
+	uint32 transColor = _engine->GetBitmapTransparentColor(src);
+	int srcPitch = _engine->GetBitmapPitch(src);
+	int destPitch = _engine->GetBitmapPitch(dest);
+
+	_engine->GetBitmapDimensions(src, &srcWidth, &srcHeight, &srcColDepth);
+	_engine->GetBitmapDimensions(dest, &destWidth, &destHeight, &destColDepth);
+
+	int bpp = destColDepth / 8;
+
+	if (srcy + height > srcHeight || srcx + width > srcWidth || srcx < 0 || srcy < 0) return;
+
+	if (width + destx > destWidth) width = destWidth - destx;
+	if (height + desty > destHeight) height = destHeight - desty;
+
+	int startx = MAX(0, (-1 * destx));
+	int starty = MAX(0, (-1 * desty));
+
+
+	int srca, srcr, srcg, srcb, desta, destr, destg, destb, finalr, finalg, finalb, finala, col, col_r, col_g, col_b;
+	col_r = getr32(colour);
+	col_g = getg32(colour);
+	col_b = getb32(colour);
+
+	int srcxx = (startx + srcx) * bpp;
+	int destxx = (startx + destx) * bpp;
+	for (int x = startx; x < width; ++x, srcxx += bpp, destxx += bpp) {
+
+		int srcyy =  (starty + srcy) * srcPitch;
+		int destyy = (starty + desty) * destPitch;
+		for (int y = starty; y <  height; ++y, srcyy += srcPitch, destyy += destPitch) {
+			uint8 *srcCol = srccharbuffer + srcyy + srcxx;
+			uint8 * destCol = destcharbuffer + destyy + destxx;
+			if (destColDepth == 8) {
+				if (*srcCol != transColor)
+					*destCol = *srcCol;
+			} else if (destColDepth == 16) {
+				if (*((uint16*)srcCol) != transColor)
+					*((uint16*)destCol) = *((uint16*)srcCol);
+			} else if (destColDepth == 32) {
+				//if (*((uint32*)srcCol) != transColor)
+				//	*((uint32*)destCol) = *((uint32*)srcCol);
+
+				uint32 srcargb = *((uint32*)srcCol);
+				uint32& destargb = *((uint32*)destCol);
+
+				srca = (geta32(srcargb));
+
+				if (srca != 0) {
+
+					srcr =  getr32(srcargb);
+					srcg =  getg32(srcargb);
+					srcb =  getb32(srcargb);
+
+					destr =  getr32(destargb);
+					destg =  getg32(destargb);
+					destb =  getb32(destargb);
+					desta =  geta32(destargb);
+
+					finalr = (col_r * srcr) / 255;
+					finalg = (col_g * srcg) / 255;
+					finalb = (col_b * srcb) / 255;
+
+					finala = 255 - (255 - srca) * (255 - desta) / 255;
+					finalr = srca * finalr / finala + desta * destr * (255 - srca) / finala / 255;
+					finalg = srca * finalg / finala + desta * destg * (255 - srca) / finala / 255;
+					finalb = srca * finalb / finala + desta * destb * (255 - srca) / finala / 255;
+					col = makeacol32(finalr, finalg, finalb, finala);
+					destargb = col;
+				}
+
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+	_engine->ReleaseBitmapSurface(dest);
+}
+
+} // namespace AGSSpriteFont
+} // namespace Plugins
+} // namespace AGS3
diff --git a/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.h b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.h
new file mode 100644
index 0000000000..c4737882aa
--- /dev/null
+++ b/engines/ags/plugins/ags_sprite_font/variable_width_sprite_font_clifftop.h
@@ -0,0 +1,50 @@
+
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or(at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef AGS_PLUGINS_AGS_SPRITE_FONT_VAR_WIDTH_SPR_FONT_CLIFFTOP_H
+#define AGS_PLUGINS_AGS_SPRITE_FONT_VAR_WIDTH_SPR_FONT_CLIFFTOP_H
+
+#include "ags/plugins/ags_sprite_font/variable_width_sprite_font.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSSpriteFont {
+
+class VariableWidthSpriteFontRendererClifftop : public VariableWidthSpriteFontRenderer {
+public:
+	VariableWidthSpriteFontRendererClifftop(IAGSEngine *engine);
+	virtual ~VariableWidthSpriteFontRendererClifftop(void);
+
+	int GetTextHeight(const char *text, int fontNumber) override;
+	void RenderText(const char *text, int fontNumber, BITMAP *destination, int x, int y, int colour) override;
+
+private:
+	void Draw(BITMAP *src, BITMAP *dest, int destx, int desty, int srcx, int srcy, int width, int height, int colour);
+};
+
+} // namespace AGSSpriteFont
+} // namespace Plugins
+} // namespace AGS3
+
+
+#endif


Commit: e7d51b856de33783fae0f1ef18c21bab34eee2fb
    https://github.com/scummvm/scummvm/commit/e7d51b856de33783fae0f1ef18c21bab34eee2fb
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2021-03-06T21:21:22Z

Commit Message:
AGS: Use AGSSpritePlugin variant for Kathy Rain and WoaM

Changed paths:
    engines/ags/detection.h
    engines/ags/detection_tables.h
    engines/ags/plugins/plugin_base.cpp


diff --git a/engines/ags/detection.h b/engines/ags/detection.h
index b461781bc6..f47c24c42b 100644
--- a/engines/ags/detection.h
+++ b/engines/ags/detection.h
@@ -42,6 +42,7 @@ extern const PlainGameDescriptor GAME_NAMES[];
 extern const AGSGameDescription GAME_DESCRIPTIONS[];
 
 enum AGSSteamVersion { kAGSteam = 0, kBlackwell = 1 };
+enum AGSSpriteFontVersion { kAGSSpriteFont = 0, kClifftopGames = 1 };
 
 } // namespace AGS
 
diff --git a/engines/ags/detection_tables.h b/engines/ags/detection_tables.h
index 8ce9586360..362b6f1110 100644
--- a/engines/ags/detection_tables.h
+++ b/engines/ags/detection_tables.h
@@ -1444,6 +1444,8 @@ const PlainGameDescriptor GAME_NAMES[] = {
 
 static const PluginVersion AGSTEAM_BLACKWELL[] = { { "agsteam", kBlackwell }, { nullptr, 0 } };
 static const PluginVersion AGS_FLASHLIGHT[] = { { "agsflashlight", 0 }, { nullptr, 0 } };
+static const PluginVersion AGSSPRITEFONT_CLIFFTOP[] = { { "agsspritefont", kClifftopGames }, { nullptr, 0 } };
+
 
 const AGSGameDescription GAME_DESCRIPTIONS[] = {
 	// Pre-2.5 games that aren't supported by the current AGS engine
@@ -1750,8 +1752,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = {
 	GAME_ENTRY("waitingfortheloop", "waitingfortheloop.exe", "0241777c2537fc5d077c05cde10bfa9f", 51472537), // Steam
 	GAME_ENTRY("waitingfortheloop", "waitingfortheloop.exe", "0241777c2537fc5d077c05cde10bfa9f", 51273604),
 	GAME_ENTRY("welcometosunnymunarvagir", "alpha4.ags", "392dbdd0697ae32af4cfe5212f9213c5", 23000263),
-	GAME_ENTRY("whispersofamachine", "whispers.exe", "b4962a0a9c9c33954e185a137125f527", 159084291), // Steam
-	GAME_ENTRY("whispersofamachine", "whispers.exe", "b8416ff5242d6540980f922f03a01a5f", 159085573), // GOG
+	GAME_ENTRY_PLUGIN("whispersofamachine", "whispers.exe", "b4962a0a9c9c33954e185a137125f527", 159084291, AGSSPRITEFONT_CLIFFTOP), // Steam
+	GAME_ENTRY_PLUGIN("whispersofamachine", "whispers.exe", "b8416ff5242d6540980f922f03a01a5f", 159085573, AGSSPRITEFONT_CLIFFTOP), // GOG
 	GAME_ENTRY("zniwadventure", "ctgame.exe", "8a2d48ee8d92bad3c5cacd8b883c5871", 100036465), // Steam
 
 	// Post-2.5 games that are likely supported by the AGS engine
@@ -2350,9 +2352,9 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = {
 	GAME_ENTRY("justanotherpointnclickadventure", "Advent.exe", "6a98b4cc2f5a55421248be53f15a6a99", 9582620),
 	GAME_ENTRY("kanjigakusei", "KanjiGakusei.exe", "c1bce0ccfa858f0f5d2fe19997d89b05", 17604764),
 	GAME_ENTRY("kartquest", "Kart.exe", "465f972675db2da6040518221af5b0ba", 77317312),
-	GAME_ENTRY("kathyrain", "kathyrain.exe", "434e24a12ba3cfb07d7b4b2f0e0bb1bf", 197487159), // Steam
-	GAME_ENTRY("kathyrain", "kathyrain.exe", "d2b1ba151c3d209b50331127032f96f6", 197490245), // GOG 1.04
-	GAME_ENTRY("kathyrain", "kathyrain.exe", "d2b1ba151c3d209b50331127032f96f6", 197489719), // GOG
+	GAME_ENTRY_PLUGIN("kathyrain", "kathyrain.exe", "434e24a12ba3cfb07d7b4b2f0e0bb1bf", 197487159, AGSSPRITEFONT_CLIFFTOP), // Steam
+	GAME_ENTRY_PLUGIN("kathyrain", "kathyrain.exe", "d2b1ba151c3d209b50331127032f96f6", 197490245, AGSSPRITEFONT_CLIFFTOP), // GOG 1.04
+	GAME_ENTRY_PLUGIN("kathyrain", "kathyrain.exe", "d2b1ba151c3d209b50331127032f96f6", 197489719, AGSSPRITEFONT_CLIFFTOP), // GOG
 	GAME_ENTRY("keptoshi", "Keptosh.exe", "95b7dd55f6e15c8a2118856ed9fe8ff9", 2904848),
 	GAME_ENTRY("keys", "Keys.exe", "75f4c7f66b1be60af5b2d65f617b91a7", 85582285),
 	GAME_ENTRY("killereye", "killereye.exe", "0710e2ec71042617f565c01824f0cf3c", 1009042),
diff --git a/engines/ags/plugins/plugin_base.cpp b/engines/ags/plugins/plugin_base.cpp
index 4a3235fe4a..fd78c2bfe7 100644
--- a/engines/ags/plugins/plugin_base.cpp
+++ b/engines/ags/plugins/plugin_base.cpp
@@ -32,6 +32,7 @@
 #include "ags/plugins/ags_pal_render/ags_pal_render.h"
 #include "ags/plugins/ags_snow_rain/ags_snow_rain.h"
 #include "ags/plugins/ags_sprite_font/ags_sprite_font.h"
+#include "ags/plugins/ags_sprite_font/ags_sprite_font_clifftop.h"
 #include "ags/plugins/ags_tcp_ip/ags_tcp_ip.h"
 #include "ags/plugins/ags_wadjet_util/ags_wadjet_util.h"
 #include "ags/ags.h"
@@ -78,6 +79,9 @@ void *pluginOpen(const char *filename) {
 	if (fname.equalsIgnoreCase("AGSSnowRain") || fname.equalsIgnoreCase("ags_snowrain"))
 		return new AGSSnowRain::AGSSnowRain();
 
+	if ((fname.equalsIgnoreCase("AGSSpriteFont") && version == ::AGS::kClifftopGames))
+		return new AGSSpriteFont::AGSSpriteFontClifftopGames();
+
 	if (fname.equalsIgnoreCase("AGSSpriteFont") || fname.equalsIgnoreCase("agsplugin.spritefont"))
 		return new AGSSpriteFont::AGSSpriteFont();
 




More information about the Scummvm-git-logs mailing list