[Scummvm-git-logs] scummvm master -> 6a4062d3fc75e888ba293c860e54b59c3b12f3f3

dreammaster dreammaster at scummvm.org
Wed Jul 21 03:27:26 UTC 2021


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

Summary:
930be67a9f AGS: Adding AGSWaves draw methods
74be1d8fd7 AGS: Further fleshing out AGSWaves gfx methods
f5afbc964d AGS: Implemented AGSWaves weather methods
aadd100b9c AGS: Implementing AGSWaves sound methods
6a4062d3fc AGS: Fix some comments in call_function


Commit: 930be67a9f25d767837ce788e03a8924743dc4cb
    https://github.com/scummvm/scummvm/commit/930be67a9f25d767837ce788e03a8924743dc4cb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-20T20:25:53-07:00

Commit Message:
AGS: Adding AGSWaves draw methods

Changed paths:
    engines/ags/plugins/ags_waves/ags_waves.cpp
    engines/ags/plugins/ags_waves/ags_waves.h
    engines/ags/plugins/ags_waves/draw.cpp
    engines/ags/plugins/ags_waves/vars.h


diff --git a/engines/ags/plugins/ags_waves/ags_waves.cpp b/engines/ags/plugins/ags_waves/ags_waves.cpp
index 1c879ec951..b995fc7d71 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.cpp
+++ b/engines/ags/plugins/ags_waves/ags_waves.cpp
@@ -99,11 +99,6 @@ void AGSWaves::AGS_EngineStartup(IAGSEngine *engine) {
 	SCRIPT_METHOD(SetWalkbehindBaserine, AGSWaves::SetWalkbehindBaserine);
 }
 
-void AGSWaves::DrawScreenEffect(ScriptMethodParams &params) {
-	PARAMS4(int, sprite, int, sprite_prev, int, ide, int, n);
-	DrawEffect(sprite, sprite_prev, ide, n);
-}
-
 void AGSWaves::SFX_Play(ScriptMethodParams &params) {
 	//PARAMS2(int, SFX, int, repeat);
 }
@@ -160,22 +155,6 @@ void AGSWaves::SFX_Filter(ScriptMethodParams &params) {
 	//PARAMS2(int, SFX, int, enable);
 }
 
-void AGSWaves::DrawBlur(ScriptMethodParams &params) {
-	//PARAMS2(int, spriteD, int, radius);
-}
-
-void AGSWaves::DrawTunnel(ScriptMethodParams &params) {
-	//PARAMS3(int, spriteD, float, scale, float, speed);
-}
-
-void AGSWaves::DrawCylinder(ScriptMethodParams &params) {
-	//PARAMS2(int, spriteD, int, ogsprite);
-}
-
-void AGSWaves::DrawForceField(ScriptMethodParams &params) {
-	//PARAMS4(int, spriteD, int, scale, float, speed, int, id);
-}
-
 void AGSWaves::Grayscale(ScriptMethodParams &params) {
 	//PARAMS1(int, sprite);
 }
diff --git a/engines/ags/plugins/ags_waves/ags_waves.h b/engines/ags/plugins/ags_waves/ags_waves.h
index 5b4e646172..1d1eb163cc 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.h
+++ b/engines/ags/plugins/ags_waves/ags_waves.h
@@ -90,6 +90,31 @@ private:
 	void CastWave(int delayMax, int PixelsWide, int n);
 	void DrawEffect(int sprite_a, int sprite_b, int id, int n);
 
+	inline static int getRcolor(int color) {
+		return ((color >> 16) & 0xFF);
+	}
+	inline static int getGcolor(int color) {
+		return ((color >> 8) & 0xFF);
+	}
+	inline static int getBcolor(int color) {
+		return ((color >> 0) & 0xFF);
+	}
+	inline static int getAcolor(int color) {
+		return ((color >> 24) & 0xFF);
+	}
+	static int SetColorRGBA(int r, int g, int b, int a);
+	float noiseField(float tx, float ty, float tz);
+
+
+	static inline float fracts(float value) {
+		return value - floor(value);
+	}
+	static inline float lerp(float x, float y, float fn) {
+		return x * (1.0 - fn) + y * fn;
+	}
+	static inline float hasher(float n) {
+		return fracts(sin(n) * 153.5453123);
+	}
 public:
 	AGSWaves() : PluginBase(), Vars() {}
 	virtual ~AGSWaves() {}
diff --git a/engines/ags/plugins/ags_waves/draw.cpp b/engines/ags/plugins/ags_waves/draw.cpp
index 53a7fe9fdd..35ca05c513 100644
--- a/engines/ags/plugins/ags_waves/draw.cpp
+++ b/engines/ags/plugins/ags_waves/draw.cpp
@@ -20,6 +20,7 @@
  *
  */
 
+#include "common/util.h"
 #include "ags/plugins/ags_waves/ags_waves.h"
 #include "ags/ags.h"
 
@@ -27,6 +28,299 @@ namespace AGS3 {
 namespace Plugins {
 namespace AGSWaves {
 
+void AGSWaves::DrawScreenEffect(ScriptMethodParams &params) {
+	PARAMS4(int, sprite, int, sprite_prev, int, ide, int, n);
+	DrawEffect(sprite, sprite_prev, ide, n);
+}
+
+void AGSWaves::DrawBlur(ScriptMethodParams &params) {
+	PARAMS2(int, spriteD, int, radius);
+
+	int spriteD2 = spriteD;
+	BITMAP *src = _engine->GetSpriteGraphic(spriteD);
+	BITMAP *src2 = _engine->GetSpriteGraphic(spriteD2);
+
+	uint32 **pixelb = (uint32 **)_engine->GetRawBitmapSurface(src);
+	uint32 **pixela = (uint32 **)_engine->GetRawBitmapSurface(src2);
+	_engine->ReleaseBitmapSurface(src2);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+
+	int x, y;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int totalRed = 0;
+			int totalGreen = 0;
+			int totalBlue = 0;
+
+			int vx = -(radius);
+			int pixels_parsed = 0;
+
+			int setY = y;
+			if (setY < 0) setY = 0;
+			if (setY > src_height - 1) setY = src_height - 1;
+
+			while (vx < (radius)+1) {
+				int setX = x + vx;
+				if (setX < 0) setX = 0;
+				if (setX > src_width - 1) setX = src_width - 1;
+
+
+				int color = pixela[setY][setX];
+
+				totalRed += getRcolor(color);
+				totalGreen += getGcolor(color);
+				totalBlue += getBcolor(color);
+
+				pixels_parsed++;
+				vx++;
+			}
+
+			int rN = totalRed / pixels_parsed;
+			int gN = totalGreen / pixels_parsed;
+			int bN = totalBlue / pixels_parsed;
+
+			int r = CLIP(rN, 0, 255);
+			int g = CLIP(gN, 0, 255);
+			int b = CLIP(bN, 0, 255);
+
+			pixelb[y][x] = ((r << 16) | (g << 8) | (b << 0) | (255 << 24));
+		}
+	}
+
+
+	_engine->ReleaseBitmapSurface(src);
+	src = _engine->GetSpriteGraphic(spriteD);
+
+	x = 0;
+	y = 0;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int totalRed = 0;
+			int totalGreen = 0;
+			int totalBlue = 0;
+
+			int pixels_parsed = 0;
+			int setX = x;
+			if (setX < 0) setX = 0;
+			if (setX > src_width - 1) setX = src_width - 1;
+
+			int vy = -(radius);
+			while (vy < (radius)+1) {
+				int setY = y + vy;
+				if (setY < 0) setY = 0;
+				if (setY > src_height - 1) setY = src_height - 1;
+
+				int color = pixela[setY][setX];
+
+				totalRed += getRcolor(color);
+				totalGreen += getGcolor(color);
+				totalBlue += getBcolor(color);
+
+				pixels_parsed++;
+
+				vy++;
+			}
+
+			int rN = totalRed / pixels_parsed;
+			int gN = totalGreen / pixels_parsed;
+			int bN = totalBlue / pixels_parsed;
+
+			int r = CLIP(rN, 0, 255);
+			int g = CLIP(gN, 0, 255);
+			int b = CLIP(bN, 0, 255);
+
+			pixelb[y][x] = ((r << 16) | (g << 8) | (b << 0) | (255 << 24));
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::DrawTunnel(ScriptMethodParams &params) {
+	PARAMS3(int, spriteD, float, scale, float, speed);
+
+	d_time = speed;
+	BITMAP *src = _engine->GetSpriteGraphic(spriteD);
+	uint32 **pixela = (uint32 **)_engine->GetRawBitmapSurface(src);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	BITMAP *src2 = _engine->GetSpriteGraphic(int(scale));
+	uint32 **pixelb = (uint32 **)_engine->GetRawBitmapSurface(src2);
+	int h = screenHeight;
+	int w = screenWidth;
+	if (!generateonce) {
+		generateonce = true;
+		//generate texture
+		for (int y = 0; y < texHeight; y++) {
+			for (int x = 0; x < texWidth; x++) {
+				texture[y][x] = pixelb[y][x];
+			}
+		}
+
+		//generate non-linear transformation table
+		for (int y = 0; y < h; y++) {
+			for (int x = 0; x < w; x++) {
+				int angle, distance;
+				float ratio = 32.0;
+				distance = int(ratio * texHeight / sqrt((x - w / 2.0) * (x - w / 2.0) + (y - h / 2.0) * (y - h / 2.0))) % texHeight;
+				angle = (uint32)(0.5 * texWidth * atan2(y - h / 2.0, x - w / 2.0) / 3.1416);
+				distanceTable[y][x] = distance;///4.0;
+				angleTable[y][x] = angle;
+			}
+		}
+	}
+
+	int shiftX = int(texWidth * 0.75 * d_time);
+	int shiftY = int(texHeight * 1.0 * d_time);
+
+	for (int y = 0; y < h; y++) {
+		for (int x = 0; x < w; x++) {
+			//get the texel from the texture by using the tables, shifted with the animation values
+			int color = texture[(uint32)(distanceTable[y][x] + shiftX) % texWidth][(uint32)(angleTable[y][x] + shiftY) % texHeight];
+
+			pixela[y][x] = color;
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src2);
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::DrawCylinder(ScriptMethodParams &params) {
+	PARAMS2(int, spriteD, int, ogsprite);
+
+	BITMAP *src = _engine->GetSpriteGraphic(spriteD);
+	uint32 **pixela = (uint32 **)_engine->GetRawBitmapSurface(src);
+	int src_width = 640;
+	int src_height = 640;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	BITMAP *src2 = _engine->GetSpriteGraphic(ogsprite);
+	uint32 **pixelb = (uint32 **)_engine->GetRawBitmapSurface(src2);
+	_engine->ReleaseBitmapSurface(src2);
+	int height = src_height;
+	int width = src_width;
+
+	for (int y = 0; y < height; y++) {
+		for (int x = 0; x < width; x++) {
+			//convertPoint(x,y,width,height);
+
+			//center the point at 0,0
+			float pcx = x - width / 2;
+			float pcy = y - height / 2;
+
+			//these are your free parameters
+			float f = width / 2;
+			float r = width;
+
+			float omega = width / 2;
+			float z0 = f - sqrt(r * r - omega * omega);
+			float zc = (2 * z0 + sqrt(4 * z0 * z0 - 4 * (pcx * pcx / (f * f) + 1) * (z0 * z0 - r * r))) / (2 * (pcx * pcx / (f * f) + 1));
+
+			float finalpointx = pcx * zc / f;
+			float finalpointy = pcy * zc / f;
+			finalpointx += width / 2;
+			finalpointy += height / 2;
+
+
+			int cposx = finalpointx;
+			int cposy = finalpointy;
+			if (cposx < 0 ||
+				cposx > width - 1 ||
+				cposy < 0 ||
+				cposy > height - 1) {
+				pixela[y][x] = SetColorRGBA(0, 0, 0, 0);
+			} else {
+				pixela[y][x] = pixelb[cposy][cposx];
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::DrawForceField(ScriptMethodParams &params) {
+	PARAMS4(int, spriteD, int, scale, float, speed, int, id);
+
+	if (id < 0 || id >4) {
+		return;
+	}
+	if (b_time[id] == NULL) b_time[id] = 1.0;
+	if (b_time[id] < 1.0) b_time[id] = 1.0;
+	b_time[id] += speed;
+	BITMAP *src = _engine->GetSpriteGraphic(spriteD);
+
+	uint32 **pixelb = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+
+	int x, y;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int setY = y;
+			if (setY < 0) setY = 0;
+			int setX = x;
+			if (setX < 0) setX = 0;
+
+			float uvx = float(x) / float(scale);
+			float uvy = float(y) / float(scale);
+
+			float jx = uvx;
+			float jy = uvy + b_time[id] * 3.14;
+			float jz = sin(b_time[id]);
+			float jyy = uvy + b_time[id];
+			float jzz = cos(b_time[id] + 3.0);
+
+			float af = ABS(noiseField(jx, jy, jz) - noiseField(jx, jyy, jzz));
+			float newR = 0.5 - pow(af, float(0.2)) / 2.0;
+			float newG = 0.0;
+			float newB = 0.4 - pow(af, float(0.4));
+
+			int Rd = int(newR * 255.0);
+			int Gd = int(newG * 255.0);
+			int Bd = int(newB * 255.0);
+			int na = int(1.0 * 255.0);//pixelb[setY][setX];//int(1.0*255.0);
+
+			int highest = 0;
+			if (Rd > Gd) {
+				if (Rd > Bd) highest = Rd;
+				else highest = Bd;
+			} else {
+				if (Gd > Bd) highest = Gd;
+				else highest = Bd;
+			}
+
+			int grabA = getAcolor(pixelb[setY][setX]);
+
+			if (highest <= 40) {
+				na = int((float(highest * 2) / 100.0) * 255.0);
+			} else {
+				na = grabA;
+			}
+			pixelb[setY][setX] = SetColorRGBA(Rd, Gd, Bd, na);//
+
+
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+
 void AGSWaves::CastWave(int delayMax, int PixelsWide, int n) {
 	tDy[n]++;
 	if (tDy[n] > delayMax) {
@@ -134,6 +428,32 @@ void AGSWaves::DrawEffect(int sprite_a, int sprite_b, int id, int n) {
 	_engine->ReleaseBitmapSurface(src_b);
 }
 
+int AGSWaves::SetColorRGBA(int r, int g, int b, int a) {
+	r = CLIP(r, 0, 255);
+	g = CLIP(g, 0, 255);
+	b = CLIP(b, 0, 255);
+	a = CLIP(a, 0, 255);
+	return int((r << 16) | (g << 8) | (b << 0) | (a << 24));
+}
+
+float AGSWaves::noiseField(float tx, float ty, float tz) {
+	float px = floor(tx);
+	float fx = fracts(tx);
+	float py = floor(ty);
+	float fy = fracts(ty);
+	float pz = floor(tz);
+	float fz = fracts(tz);
+	fx = fx * fx * (3.0 - 2.0 * fx);
+	fy = fy * fy * (3.0 - 2.0 * fy);
+	fz = fz * fz * (3.0 - 2.0 * fz);
+
+	float n = px + py * 157.0 + 113.0 * pz;
+	return lerp(lerp(lerp(hasher(n + 0.0), hasher(n + 1.0), fx),
+		lerp(hasher(n + 157.0), hasher(n + 158.0), fx), fy),
+		lerp(lerp(hasher(n + 113.0), hasher(n + 114.0), fx),
+			lerp(hasher(n + 270.0), hasher(n + 271.0), fx), fy), fz);
+}
+
 } // namespace AGSWaves
 } // namespace Plugins
 } // namespace AGS3
diff --git a/engines/ags/plugins/ags_waves/vars.h b/engines/ags/plugins/ags_waves/vars.h
index 45f4726649..8fced69c75 100644
--- a/engines/ags/plugins/ags_waves/vars.h
+++ b/engines/ags/plugins/ags_waves/vars.h
@@ -156,13 +156,13 @@ struct Vars {
 	int movedport;
 	int translay;
 	int translayHold;
-	int width;
-	int height;
-	int fx;
-	int fy;
+	int _width;
+	int _height;
+	int _fx;
+	int _fy;
 	bool doingcircle;
-	float angle;
-	float radius;
+	float _angle;
+	float _radius;
 	int doingCircleChance;
 	float angleLay;
 	int frame;


Commit: 74be1d8fd7d64bd847e6d0c5c98d9869b821bb7b
    https://github.com/scummvm/scummvm/commit/74be1d8fd7d64bd847e6d0c5c98d9869b821bb7b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-20T20:25:53-07:00

Commit Message:
AGS: Further fleshing out AGSWaves gfx methods

Changed paths:
  A engines/ags/plugins/ags_waves/data.cpp
  A engines/ags/plugins/ags_waves/sound.cpp
  A engines/ags/plugins/ags_waves/warper.cpp
    engines/ags/module.mk
    engines/ags/plugins/ags_waves/ags_waves.cpp
    engines/ags/plugins/ags_waves/ags_waves.h
    engines/ags/plugins/ags_waves/draw.cpp
    engines/ags/plugins/ags_waves/vars.h


diff --git a/engines/ags/module.mk b/engines/ags/module.mk
index 6f057102c3..5d3c4ef7ac 100644
--- a/engines/ags/module.mk
+++ b/engines/ags/module.mk
@@ -352,7 +352,10 @@ MODULE_OBJS = \
 	plugins/ags_tcp_ip/ags_tcp_ip.o \
 	plugins/ags_wadjet_util/ags_wadjet_util.o \
 	plugins/ags_waves/ags_waves.o \
-	plugins/ags_waves/draw.o
+	plugins/ags_waves/data.o \
+	plugins/ags_waves/draw.o \
+	plugins/ags_waves/sound.o \
+	plugins/ags_waves/warper.o
 
 ifdef ENABLE_AGS_TESTS
 MODULE_OBJS += \
diff --git a/engines/ags/plugins/ags_waves/ags_waves.cpp b/engines/ags/plugins/ags_waves/ags_waves.cpp
index b995fc7d71..d8ebbf13f2 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.cpp
+++ b/engines/ags/plugins/ags_waves/ags_waves.cpp
@@ -26,9 +26,9 @@ namespace AGS3 {
 namespace Plugins {
 namespace AGSWaves {
 
-const unsigned int Magic = 0xACAB0000;
-const unsigned int Version = 1;
-const unsigned int SaveMagic = Magic + Version;
+const uint32 Magic = 0xACAB0000;
+const uint32 Version = 1;
+const uint32 SaveMagic = Magic + Version;
 const float PI = 3.14159265f;
 
 const char *AGSWaves::AGS_GetPluginName() {
@@ -99,161 +99,6 @@ void AGSWaves::AGS_EngineStartup(IAGSEngine *engine) {
 	SCRIPT_METHOD(SetWalkbehindBaserine, AGSWaves::SetWalkbehindBaserine);
 }
 
-void AGSWaves::SFX_Play(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, repeat);
-}
-
-void AGSWaves::SFX_SetVolume(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, volume);
-}
-
-void AGSWaves::SFX_GetVolume(ScriptMethodParams &params) {
-	//PARAMS1(int, SFX);
-	params._result = 0;
-}
-
-void AGSWaves::Music_Play(ScriptMethodParams &params) {
-	//PARAMS6(int, MFX, int, repeat, int, fadeinMS, int, fadeoutMS, int, Position, bool, fixclick);
-}
-
-void AGSWaves::Music_SetVolume(ScriptMethodParams &params) {
-	//PARAMS1(int, volume);
-}
-
-void AGSWaves::Music_GetVolume(ScriptMethodParams &params) {
-	params._result = 0;
-}
-
-void AGSWaves::SFX_Stop(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, fademsOUT);
-}
-
-void AGSWaves::SFX_SetPosition(ScriptMethodParams &params) {
-	//PARAMS4(int, SFX, int, x, int, y, int, intensity);
-}
-
-void AGSWaves::SFX_SetGlobalVolume(ScriptMethodParams &params) {
-	//PARAMS1(int, volume);
-}
-
-void AGSWaves::Load_SFX(ScriptMethodParams &params) {
-	//PARAMS1(int, SFX);
-}
-
-void AGSWaves::Audio_Apply_Filter(ScriptMethodParams &params) {
-	//PARAMS1(int, Frequency);
-}
-
-void AGSWaves::Audio_Remove_Filter(ScriptMethodParams &params) {
-}
-
-void AGSWaves::SFX_AllowOverlap(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, allow);
-}
-
-void AGSWaves::SFX_Filter(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, enable);
-}
-
-void AGSWaves::Grayscale(ScriptMethodParams &params) {
-	//PARAMS1(int, sprite);
-}
-
-void AGSWaves::ReadWalkBehindIntoSprite(ScriptMethodParams &params) {
-	//PARAMS3(int, sprite, int, bgsprite, int, walkbehindBaseline);
-}
-
-void AGSWaves::AdjustSpriteFont(ScriptMethodParams &params) {
-	//PARAMS5(int, sprite, int, rate, int, outlineRed, int, outlineGreen, int, outlineBlue);
-}
-
-void AGSWaves::SpriteGradient(ScriptMethodParams &params) {
-	//PARAMS3(int, sprite, int, rate, int, toy);
-}
-
-void AGSWaves::Outline(ScriptMethodParams &params) {
-	//PARAMS5(int, sprite, int, red, int, ged, int, bed, int, aed);
-}
-
-void AGSWaves::OutlineOnly(ScriptMethodParams &params) {
-	//PARAMS7(int, sprite, int, refsprite, int, red, int, ged, int, bed, int, aed, int, trans);
-}
-
-void AGSWaves::SaveVariable(ScriptMethodParams &params) {
-	//PARAMS2(const char *, value, int, id);
-}
-
-void AGSWaves::ReadVariable(ScriptMethodParams &params) {
-	//PARAMS1(int, id);
-	params._result = (const char *)nullptr;
-}
-
-void AGSWaves::GameDoOnceOnly(ScriptMethodParams &params) {
-//	PARAMS1(const char *, value);
-
-	GetGDState(params);
-	if (params._result) {
-		// Set state to false
-		params.push_back(false);
-		SetGDState(params);
-
-		params._result = true;
-	} else {
-		params._result = false;
-	}
-}
-
-void AGSWaves::SetGDState(ScriptMethodParams &params) {
-	PARAMS2(const char *, value, bool, setValue);
-
-	int id = -1;
-	for (int i = 0; i <= usedTokens; i++) {
-		if (Token[i] != NULL && strcmp(Token[i], value) == 0) {
-			id = i;
-			TokenUnUsed[i] = setValue;
-			i = usedTokens + 1;
-		}
-	}
-
-	if (id == -1) {
-		// It doesn't find it while trying to set its state
-		// create the thing with said state
-		id = usedTokens;
-		TokenUnUsed[id] = setValue;
-		if (Token[id] != NULL)
-			free(Token[id]);
-
-		Token[id] = scumm_strdup(value);
-		usedTokens++;
-	}
-}
-
-void AGSWaves::GetGDState(ScriptMethodParams &params) {
-	PARAMS1(const char *, value);
-
-	int id = -1;
-
-	for (int i = 0; i <= usedTokens; i++) {
-		if (Token[i] != NULL && strcmp(Token[i], value) == 0) {
-			id = i;
-			i = usedTokens + 1;
-		}
-	}
-
-	if (id == -1) {
-		params._result = true;
-	} else {
-		params._result = TokenUnUsed[id];
-	}
-}
-
-void AGSWaves::ResetAllGD(ScriptMethodParams &params) {
-}
-
-void AGSWaves::SpriteSkew(ScriptMethodParams &params) {
-	//PARAMS5(int, sprite, float, xskewmin, float, yskewmin, float, xskewmax, float, yskewmax);
-}
-
 void AGSWaves::FireUpdate(ScriptMethodParams &params) {
 	//PARAMS2(int, getDynamicSprite, bool, Fire2Visible));
 }
@@ -266,67 +111,14 @@ void AGSWaves::SetWindValues(ScriptMethodParams &params) {
 	//PARAMS4(int, w, int, h, int, pr, int, prev);
 }
 
-void AGSWaves::ReturnWidth(ScriptMethodParams &params) {
-	//PARAMS8(int, x1, int, y1, int, x2, int, y2, int, x3, int, y3, int, x4, int, y4);
-	params._result = 0;
-}
-
-void AGSWaves::ReturnHeight(ScriptMethodParams &params) {
-	//PARAMS8(int, x1, int, y1, int, x2, int, y2, int, x3, int, y3, int, x4, int, y4);
-	params._result = 0;
-}
-
-void AGSWaves::ReturnNewHeight(ScriptMethodParams &params) {
-}
-
-void AGSWaves::ReturnNewWidth(ScriptMethodParams &params) {
-}
-
-void AGSWaves::Warper(ScriptMethodParams &params) {
-	//PARAMS5(int, swarp, int, sadjust, int, x1, int, y1, int, x2);
-}
-
-void AGSWaves::SetWarper(ScriptMethodParams &params) {
-	//PARAMS5(int, y2x, int, x3x, int, y3x, int, x4x, int, y4x);
-}
-
 void AGSWaves::RainUpdate(ScriptMethodParams &params) {
 	//PARAMS7(int, rdensity, int, FX, int, FY, int, RW, int, RH, int, graphic, float, perc);
 }
 
-void AGSWaves::BlendTwoSprites(ScriptMethodParams &params) {
-	//PARAMS2(int, graphic, int, refgraphic);
-}
-
-void AGSWaves::Blend(ScriptMethodParams &params) {
-	//PARAMS4(int, graphic, int, refgraphic, bool, screen, int, perc);
-}
-
-void AGSWaves::Dissolve(ScriptMethodParams &params) {
-	//PARAMS3(int, graphic, int, noisegraphic, int, disvalue);
-}
-
-void AGSWaves::ReverseTransparency(ScriptMethodParams &params) {
-	//PARAMS1(int, graphic);
-}
-
 void AGSWaves::NoiseCreator(ScriptMethodParams &params) {
 	//PARAMS2(int, graphic, int, setA);
 }
 
-void AGSWaves::TintProper(ScriptMethodParams &params) {
-	//PARAMS7(int, sprite, int, lightx, int, lighty, int, radi, int, rex, int, grx, int, blx);
-}
-
-void AGSWaves::GetWalkbehindBaserine(ScriptMethodParams &params) {
-	//PARAMS1(int, id);
-	params._result = 0;
-}
-
-void AGSWaves::SetWalkbehindBaserine(ScriptMethodParams &params) {
-	//PARAMS2(int, id, int, base);
-}
-
 void AGSWaves::StartingValues() {
 	GeneralAudio.NumOfChannels = 0;
 	GeneralAudio.Initialized = false;
diff --git a/engines/ags/plugins/ags_waves/ags_waves.h b/engines/ags/plugins/ags_waves/ags_waves.h
index 1d1eb163cc..6f06bd879a 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.h
+++ b/engines/ags/plugins/ags_waves/ags_waves.h
@@ -89,6 +89,7 @@ private:
 
 	void CastWave(int delayMax, int PixelsWide, int n);
 	void DrawEffect(int sprite_a, int sprite_b, int id, int n);
+	int Random(int threshold);
 
 	inline static int getRcolor(int color) {
 		return ((color >> 16) & 0xFF);
@@ -102,9 +103,19 @@ private:
 	inline static int getAcolor(int color) {
 		return ((color >> 24) & 0xFF);
 	}
+	static int BlendColor(int Ln, int Bn, int perc) {
+		return ((Ln < 128) ? (2 * Bn * Ln / perc) : (perc - 2 * (perc - Bn) * (perc - Ln) / perc));
+	}
+	static int BlendColorScreen(int Ln, int Bn, int perc) {
+		return (Bn == perc) ? Bn :
+			MIN(perc, (Ln * Ln / (perc - Bn)));
+	}
 	static int SetColorRGBA(int r, int g, int b, int a);
+	static int ConvertColorToGrayScale(int color);
+	static bool IsPixelTransparent(int color);
 	float noiseField(float tx, float ty, float tz);
 
+	int IntersectLines(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4);
 
 	static inline float fracts(float value) {
 		return value - floor(value);
@@ -115,6 +126,12 @@ private:
 	static inline float hasher(float n) {
 		return fracts(sin(n) * 153.5453123);
 	}
+	static float min4(float m1, float m2, float m3, float m4) {
+		return MIN(MIN(m1, m2), MIN(m3, m4));
+	}
+	static float max4(float m1, float m2, float m3, float m4) {
+		return MAX(MAX(m1, m2), MAX(m3, m4));
+	}
 public:
 	AGSWaves() : PluginBase(), Vars() {}
 	virtual ~AGSWaves() {}
diff --git a/engines/ags/plugins/ags_waves/data.cpp b/engines/ags/plugins/ags_waves/data.cpp
new file mode 100644
index 0000000000..8c2eb6d5b0
--- /dev/null
+++ b/engines/ags/plugins/ags_waves/data.cpp
@@ -0,0 +1,134 @@
+/* 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 "common/util.h"
+#include "ags/plugins/ags_waves/ags_waves.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSWaves {
+
+void AGSWaves::SaveVariable(ScriptMethodParams &params) {
+	PARAMS2(const char *, value, int, id);
+
+	if (GameDatavalue[id] != nullptr) {
+		free(GameDatavalue[id]);
+	}
+	if (value != nullptr) {
+		GameDatavalue[id] = scumm_strdup(value);
+	} else {
+		GameDatavalue[id] = nullptr;
+	}
+}
+
+void AGSWaves::ReadVariable(ScriptMethodParams &params) {
+	PARAMS1(int, id);
+
+	if (GameDatavalue[id] == NULL) {
+		params._result = _engine->CreateScriptString("");
+	} else {
+		params._result = _engine->CreateScriptString(GameDatavalue[id]);
+	}
+}
+
+void AGSWaves::GameDoOnceOnly(ScriptMethodParams &params) {
+	//	PARAMS1(const char *, value);
+
+	GetGDState(params);
+	if (params._result) {
+		// Set state to false
+		params.push_back(false);
+		SetGDState(params);
+
+		params._result = true;
+	} else {
+		params._result = false;
+	}
+}
+
+void AGSWaves::SetGDState(ScriptMethodParams &params) {
+	PARAMS2(const char *, value, bool, setValue);
+
+	int id = -1;
+	for (int i = 0; i <= usedTokens; i++) {
+		if (Token[i] != nullptr && strcmp(Token[i], value) == 0) {
+			id = i;
+			TokenUnUsed[i] = setValue;
+			i = usedTokens + 1;
+		}
+	}
+
+	if (id == -1) {
+		// It doesn't find it while trying to set its state
+		// create the thing with said state
+		id = usedTokens;
+		TokenUnUsed[id] = setValue;
+		if (Token[id] != nullptr)
+			free(Token[id]);
+
+		Token[id] = scumm_strdup(value);
+		usedTokens++;
+	}
+}
+
+void AGSWaves::GetGDState(ScriptMethodParams &params) {
+	PARAMS1(const char *, value);
+
+	int id = -1;
+
+	for (int i = 0; i <= usedTokens; i++) {
+		if (Token[i] != nullptr && strcmp(Token[i], value) == 0) {
+			id = i;
+			i = usedTokens + 1;
+		}
+	}
+
+	if (id == -1) {
+		params._result = true;
+	} else {
+		params._result = TokenUnUsed[id];
+	}
+}
+
+void AGSWaves::ResetAllGD(ScriptMethodParams &params) {
+	for (int i = 0; i <= usedTokens; i++) {
+		if (Token[i] != NULL)
+			free(Token[i]);
+		Token[i] = NULL;
+		TokenUnUsed[i] = true;
+	}
+	usedTokens = 0;
+}
+
+void AGSWaves::GetWalkbehindBaserine(ScriptMethodParams &params) {
+	PARAMS1(int, id);
+	params._result = Walkbehind[id];
+}
+
+void AGSWaves::SetWalkbehindBaserine(ScriptMethodParams &params) {
+	PARAMS2(int, id, int, base);
+	Walkbehind[id] = base;
+}
+
+} // namespace AGSWaves
+} // namespace Plugins
+} // namespace AGS3
diff --git a/engines/ags/plugins/ags_waves/draw.cpp b/engines/ags/plugins/ags_waves/draw.cpp
index 35ca05c513..400cc9e148 100644
--- a/engines/ags/plugins/ags_waves/draw.cpp
+++ b/engines/ags/plugins/ags_waves/draw.cpp
@@ -320,6 +320,667 @@ void AGSWaves::DrawForceField(ScriptMethodParams &params) {
 	_engine->ReleaseBitmapSurface(src);
 }
 
+void AGSWaves::SpriteSkew(ScriptMethodParams &params) {
+	PARAMS5(int, sprite, float, xskewmin, float, yskewmin, float, xskewmax, float, yskewmax);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_src = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	_engine->ReleaseBitmapSurface(src);
+
+	BITMAP *dest = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_dest = (uint32 **)_engine->GetRawBitmapSurface(dest);
+
+	int x, y;
+
+	float raty = abs(yskewmin - yskewmax) / float(src_height * src_width);
+	float ratx = abs(xskewmin - xskewmax) / float(src_height * src_width);
+	float yskew = yskewmin;
+	float xskew = xskewmin;
+
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int ry = int((float(x) * yskew) + float(y));
+			int rx = int(float(x) + (float(y) * xskew));
+
+			if (ry > src_height - 1) ry = src_height - 1;
+			if (rx > src_width - 1) rx = src_width - 1;
+			if (rx < 0) rx = 0;
+			if (ry < 0) ry = 0;
+
+			int getColor = pixel_src[ry][rx];
+			int red = getRcolor(getColor);
+			int green = getGcolor(getColor);
+			int blue = getBcolor(getColor);
+			int alpha = getAcolor(getColor);
+
+			pixel_dest[y][x] = SetColorRGBA(red, green, blue, alpha);
+
+			if (xskewmin < xskewmax) xskew += ratx;
+			else xskew -= ratx;
+
+			if (yskewmin < yskewmax) yskew += raty;
+			else yskew -= raty;
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(dest);
+}
+
+void AGSWaves::ReturnWidth(ScriptMethodParams &params) {
+	//PARAMS8(int, x1, int, y1, int, x2, int, y2, int, x3, int, y3, int, x4, int, y4);
+	int x1 = params[0];
+	int x2 = params[2];
+	int x3 = params[4];
+	int x4 = params[6];
+
+	float ax = float(x1);
+	float bx = float(x2);
+	float cx = float(x3);
+	float dx = float(x4);
+
+	params._result = (int(max4(ax, bx, cx, dx)) + 1);
+}
+
+void AGSWaves::ReturnHeight(ScriptMethodParams &params) {
+	//PARAMS8(int, x1, int, y1, int, x2, int, y2, int, x3, int, y3, int, x4, int, y4);
+	int y1 = params[1];
+	int y2 = params[3];
+	int y3 = params[5];
+	int y4 = params[7];
+
+	float ay = float(y1);
+	float by = float(y2);
+	float cy = float(y3);
+	float dy = float(y4);
+
+	params._result = (int)max4(ay, by, cy, dy) + 1;
+}
+
+void AGSWaves::Grayscale(ScriptMethodParams &params) {
+	PARAMS1(int, sprite);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	int x, y;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int color = ConvertColorToGrayScale(pixels[y][x]);
+			pixels[y][x] = color;
+		}
+	}
+
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::BlendTwoSprites(ScriptMethodParams &params) {
+	PARAMS2(int, graphic, int, refgraphic);
+
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	BITMAP *refsrc = _engine->GetSpriteGraphic(refgraphic);
+	int refsrc_width = 640;
+	int refsrc_height = 360;
+	int refsrc_depth = 32;
+	_engine->GetBitmapDimensions(refsrc, &refsrc_width, &refsrc_height, &refsrc_depth);
+	uint32 **refsprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(refsrc);
+	_engine->ReleaseBitmapSurface(refsrc);
+
+	int x, y;
+
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int getColor = sprite_pixels[y][x];
+			int rn = getRcolor(getColor);
+			int gn = getGcolor(getColor);
+			int bn = getBcolor(getColor);
+			int an = getAcolor(getColor);
+
+			if (an > 0.0 && rn > 4 && gn > 4 && bn > 4) {
+				int getColor2 = refsprite_pixels[y][x];
+				int rj = getRcolor(getColor2);
+				int gj = getGcolor(getColor2);
+				int bj = getBcolor(getColor2);
+				int aj = getAcolor(getColor2);
+
+				if (rj > 100 || gj > 100 || bj > 100) {
+					sprite_pixels[y][x] = SetColorRGBA(rj, gj, bj, aj);
+				}
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::Blend(ScriptMethodParams &params) {
+	PARAMS4(int, graphic, int, refgraphic, bool, screen, int, perc);
+
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	BITMAP *refsrc = _engine->GetSpriteGraphic(refgraphic);
+	int refsrc_width = 640;
+	int refsrc_height = 360;
+	int refsrc_depth = 32;
+	_engine->GetBitmapDimensions(refsrc, &refsrc_width, &refsrc_height, &refsrc_depth);
+	uint32 **refsprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(refsrc);
+	_engine->ReleaseBitmapSurface(refsrc);
+
+	int x, y;
+
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int getColor = sprite_pixels[y][x];
+			int rn = getRcolor(getColor);
+			int gn = getGcolor(getColor);
+			int bn = getBcolor(getColor);
+			int an = getAcolor(getColor);
+
+			if (an >= 0.0 && rn > 4 && gn > 4 && bn > 4) {
+				int getColor2 = refsprite_pixels[y][x];
+				int rj = getRcolor(getColor2);
+				int gj = getGcolor(getColor2);
+				int bj = getBcolor(getColor2);
+				int aj = getAcolor(getColor2);
+
+				if (!screen) {
+					rj = BlendColor(rn, rj, perc);
+					gj = BlendColor(gn, gj, perc);
+					bj = BlendColor(bn, bj, perc);
+					aj = BlendColor(an, aj, perc);
+				} else {
+					rj = BlendColorScreen(rn, rj, perc);
+					gj = BlendColorScreen(gn, gj, perc);
+					bj = BlendColorScreen(bn, bj, perc);
+					aj = BlendColorScreen(an, aj, perc);
+				}
+
+				sprite_pixels[y][x] = SetColorRGBA(rj, gj, bj, aj);
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::Dissolve(ScriptMethodParams &params) {
+	PARAMS3(int, graphic, int, noisegraphic, int, disvalue);
+
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	BITMAP *noisesrc = _engine->GetSpriteGraphic(noisegraphic);
+	int noisesrc_width = 640;
+	int noisesrc_height = 360;
+	int noisesrc_depth = 32;
+	_engine->GetBitmapDimensions(noisesrc, &noisesrc_width, &noisesrc_height, &noisesrc_depth);
+	uint32 **noise_pixels = (uint32 **)_engine->GetRawBitmapSurface(noisesrc);
+	_engine->ReleaseBitmapSurface(noisesrc);
+
+	int x, y;
+
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++)//
+		{
+			int getColor = noise_pixels[y][x];
+			int gn = getRcolor(getColor);
+
+
+			int getColorx = sprite_pixels[y][x];
+			int rj = getRcolor(getColorx);
+			int gj = getGcolor(getColorx);
+			int bj = getBcolor(getColorx);
+			int originalA = getAcolor(getColorx);
+			int aj = 0;
+
+			//disvalue 0-255
+			//FOR EACH PIXEL IN THE NOISE GRAPHIC THAT IS < DISVALUE
+			if (gn < disvalue) {
+				if (gn > disvalue - 2) {
+					rj = 193 + Random(20);
+					gj = 132 + Random(20);
+					bj = 255 + Random(20);
+					aj = originalA;
+				} else if (gn > disvalue - 3) {
+					rj = 128 + Random(20);
+					gj = 0 + Random(20);
+					bj = 255 + Random(20);
+					aj = 150;
+				} else {
+					aj = 0;
+				}
+			} else aj = originalA;
+
+			if (originalA > 50) {
+				sprite_pixels[y][x] = SetColorRGBA(rj, gj, bj, aj);
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::ReverseTransparency(ScriptMethodParams &params) {
+	PARAMS1(int, graphic);
+
+	BITMAP *noisesrc = _engine->GetSpriteGraphic(graphic);
+	int noisesrc_width = 640;
+	int noisesrc_height = 360;
+	int noisesrc_depth = 32;
+	_engine->GetBitmapDimensions(noisesrc, &noisesrc_width, &noisesrc_height, &noisesrc_depth);
+	uint32 **noise_pixels = (uint32 **)_engine->GetRawBitmapSurface(noisesrc);
+	_engine->ReleaseBitmapSurface(noisesrc);
+
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int x, y;
+
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int getColors = noise_pixels[y][x];
+			int TranClr = getAcolor(getColors);
+
+			if (TranClr < 254) {
+				//PIXEL IS TRANSPARENT
+				sprite_pixels[y][x] = SetColorRGBA(255, 255, 255, 255);
+			} else {
+				//PIXEL IS VISIBLE
+				sprite_pixels[y][x] = SetColorRGBA(0, 0, 0, 0);
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::TintProper(ScriptMethodParams &params) {
+	PARAMS7(int, sprite, int, lightx, int, lighty, int, radi, int, rex, int, grx, int, blx);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	BITMAP *src2 = _engine->GetSpriteGraphic(lightx);
+	(void)lighty; // Unused
+
+	uint32 **pixelb = (uint32 **)_engine->GetRawBitmapSurface(src);
+	uint32 **pixela = (uint32 **)_engine->GetRawBitmapSurface(src2);
+	_engine->ReleaseBitmapSurface(src2);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	int x, y;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int totalRed = 0;
+			int totalGreen = 0;
+			int totalBlue = 0;
+
+			int vx = -(radi);
+			int pixels_parsed = 0;
+
+			int setY = y;
+			if (setY < 0) setY = 0;
+			if (setY > src_height - 1) setY = src_height - 1;
+
+			while (vx < (radi)+1) {
+				int setX = x + vx;
+				if (setX < 0) setX = 0;
+				if (setX > src_width - 1) setX = src_width - 1;
+
+				int color = pixela[setY][setX];
+
+				totalRed += getRcolor(color);
+				totalGreen += getGcolor(color);
+				totalBlue += getBcolor(color);
+
+				pixels_parsed++;
+
+				vx++;
+			}
+
+			int rN = totalRed / pixels_parsed;
+			int gN = totalGreen / pixels_parsed;
+			int bN = totalBlue / pixels_parsed;
+
+			int r = int(CLIP(rN, 0, 255));
+			int g = int(CLIP(gN, 0, 255));
+			int b = int(CLIP(bN, 0, 255));
+
+			if (r > rex &&g > grx &&b > blx) {
+				pixelb[y][x] = ((r << 16) | (g << 8) | (b << 0) | (255 << 24));
+			} else {
+				pixelb[y][x] = SetColorRGBA(rex, grx, blx, 0);
+			}
+		}
+	}
+
+
+	_engine->ReleaseBitmapSurface(src);
+	src = _engine->GetSpriteGraphic(sprite);
+
+	x = 0;
+	y = 0;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int totalRed = 0;
+			int totalGreen = 0;
+			int totalBlue = 0;
+
+			int pixels_parsed = 0;
+			int setX = x;
+			if (setX < 0) setX = 0;
+			if (setX > src_width - 1) setX = src_width - 1;
+
+			int vy = -(radi);
+			while (vy < (radi)+1) {
+				int setY = y + vy;
+				if (setY < 0) setY = 0;
+				if (setY > src_height - 1) setY = src_height - 1;
+
+				int color = pixela[setY][setX];
+
+				totalRed += getRcolor(color);
+				totalGreen += getGcolor(color);
+				totalBlue += getBcolor(color);
+
+				pixels_parsed++;
+
+
+				vy++;
+			}
+
+			int rN = totalRed / pixels_parsed;
+			int gN = totalGreen / pixels_parsed;
+			int bN = totalBlue / pixels_parsed;
+
+			int r = CLIP(rN, 0, 255);
+			int g = CLIP(gN, 0, 255);
+			int b = CLIP(bN, 0, 255);
+
+			if (r > rex &&g > grx &&b > blx) {
+				pixelb[y][x] = ((r << 16) | (g << 8) | (b << 0) | (255 << 24));
+			} else {
+				pixelb[y][x] = SetColorRGBA(rex, grx, blx, 0);
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::ReadWalkBehindIntoSprite(ScriptMethodParams &params) {
+	PARAMS3(int, sprite, int, bgsprite, int, walkbehindBaseline);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	BITMAP *bgsrc = _engine->GetSpriteGraphic(bgsprite);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	BITMAP *wbh = _engine->GetRoomMask(MASK_WALKBEHIND);
+
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+	uint32 **bgsprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(bgsrc);
+	byte *walk_pixels = _engine->GetRawBitmapSurface(wbh); //8bit
+
+	_engine->ReleaseBitmapSurface(wbh);
+	_engine->ReleaseBitmapSurface(bgsrc);
+
+	// WE GRAB ALL OF THEM INTO A BITMAP and thus we know where they are drawn
+	int x, y;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			//READ COLOR
+			if (walk_pixels[y * src_width + x] > 0) {
+				int grabBaseline = _engine->GetWalkbehindBaseline(walk_pixels[y * src_width + x]);
+
+				if (grabBaseline == walkbehindBaseline) {
+					sprite_pixels[y][x] = bgsprite_pixels[y][x];
+				}
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::AdjustSpriteFont(ScriptMethodParams &params) {
+	PARAMS5(int, sprite, int, rate, int, outlineRed, int, outlineGreen, int, outlineBlue);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_src = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	int x, y;
+
+	int px = 1;
+	bool found = false;
+	for (y = 0; y < src_height; y++) {
+		if (found) {
+			px++;
+		}
+		//if (px >12) px=12;
+		bool havefound = false;
+		for (x = 0; x < src_width; x++) {
+			int getColor = pixel_src[y][x];
+			int red = getRcolor(getColor);
+			int green = getGcolor(getColor);
+			int blue = getBcolor(getColor);
+			int alpha = getAcolor(getColor);
+
+			if (alpha < 255.0 || (red <= 10 && green <= 10 && blue <= 10)) {
+				//px=1;
+				if (alpha == 255 && (red <= 10 && green <= 10 && blue <= 10)) {
+					pixel_src[y][x] = SetColorRGBA(outlineRed, outlineGreen, outlineBlue, 255);
+				}
+			} else {
+				havefound = true;
+				found = true;
+				red -= (px * rate);
+				green -= (px * rate);
+				blue -= (px * rate);
+
+				pixel_src[y][x] = SetColorRGBA(red, green, blue, 255);
+			}
+		}
+
+		if (havefound == false) {
+			if (found) {
+				px = 1;
+				found = false;
+			}
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::SpriteGradient(ScriptMethodParams &params) {
+	PARAMS3(int, sprite, int, rate, int, toy);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_src = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	int x, y;
+	int setA = 0;
+
+	for (y = toy; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			int getColor = pixel_src[y][x];
+			int red = getRcolor(getColor);
+			int green = getGcolor(getColor);
+			int blue = getBcolor(getColor);
+			int alpha = getAcolor(getColor) + setA;
+			if (alpha > 250) alpha = 250;
+
+			if (red > 10 && green > 10 && blue > 10) {
+				pixel_src[y][x] = SetColorRGBA(red, green, blue, alpha);
+			}
+
+		}
+		setA += rate;
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::Outline(ScriptMethodParams &params) {
+	PARAMS5(int, sprite, int, red, int, ged, int, bed, int, aed);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_src = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	//OUTLINE
+	_engine->ReleaseBitmapSurface(src);
+
+
+	BITMAP *dst = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_dst = (uint32 **)_engine->GetRawBitmapSurface(dst);
+
+	int x, y;
+	for (x = 0; x < src_width; x++) {
+		for (y = 0; y < src_height; y++) {
+			if (!IsPixelTransparent(pixel_src[y][x])) {
+			} else {
+				int pcount = 0;
+				int gy = -1;
+				while (gy < 2) {
+					int gx = -1;
+					while (gx < 2) {
+						int sx = x + gx;
+						int sy = y + gy;
+
+						if (sx < 0) sx = 0;
+						if (sy < 0) sy = 0;
+						if (sx > src_width - 1) sx = src_width - 1;
+						if (sy > src_height - 1) sy = src_height - 1;
+
+						if (!IsPixelTransparent(pixel_src[sy][sx])) {
+							pcount++;
+						}
+
+						gx++;
+					}
+					gy++;
+				}
+
+				if (pcount >= 2) {
+					int colorLeft = SetColorRGBA(red, ged, bed, aed);
+					pixel_dst[y][x] = colorLeft;
+				}
+			}
+		}
+	}
+
+	// OUTLINE
+	_engine->ReleaseBitmapSurface(dst);
+}
+
+void AGSWaves::OutlineOnly(ScriptMethodParams &params) {
+	PARAMS7(int, sprite, int, refsprite, int, red, int, ged, int, bed, int, aed, int, trans);
+
+	BITMAP *src = _engine->GetSpriteGraphic(refsprite);
+	uint32 **pixel_src = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	// OUTLINE
+	_engine->ReleaseBitmapSurface(src);
+
+	BITMAP *dst = _engine->GetSpriteGraphic(sprite);
+	uint32 **pixel_dst = (uint32 **)_engine->GetRawBitmapSurface(dst);
+
+	int x, y;
+	for (x = 0; x < src_width; x++) {
+		for (y = 0; y < src_height; y++) {
+			if (!IsPixelTransparent(pixel_src[y][x])) {
+				int colorLeft = SetColorRGBA(red, ged, bed, trans);
+				pixel_dst[y][x] = colorLeft;
+			} else {
+				int pcount = 0;
+				int gy = -1;
+				while (gy < 2) {
+					int gx = -1;
+					while (gx < 2) {
+						int sx = x + gx;
+						int sy = y + gy;
+
+						if (sx < 0) sx = 0;
+						if (sy < 0) sy = 0;
+						if (sx > src_width - 1) sx = src_width - 1;
+						if (sy > src_height - 1) sy = src_height - 1;
+
+						if (!IsPixelTransparent(pixel_src[sy][sx])) {
+							pcount++;
+						}
+
+						gx++;
+					}
+					gy++;
+				}
+
+				if (pcount >= 2) {
+					int colorLeft = SetColorRGBA(red, ged, bed, aed);
+					pixel_dst[y][x] = colorLeft;
+				}
+			}
+		}
+	}
+
+	// OUTLINE
+	_engine->ReleaseBitmapSurface(dst);
+}
+
 
 void AGSWaves::CastWave(int delayMax, int PixelsWide, int n) {
 	tDy[n]++;
@@ -428,6 +1089,10 @@ void AGSWaves::DrawEffect(int sprite_a, int sprite_b, int id, int n) {
 	_engine->ReleaseBitmapSurface(src_b);
 }
 
+int AGSWaves::Random(int threshold) {
+	return ::AGS::g_vm->getRandomNumber(threshold - 1);
+}
+
 int AGSWaves::SetColorRGBA(int r, int g, int b, int a) {
 	r = CLIP(r, 0, 255);
 	g = CLIP(g, 0, 255);
@@ -454,6 +1119,22 @@ float AGSWaves::noiseField(float tx, float ty, float tz) {
 			lerp(hasher(n + 270.0), hasher(n + 271.0), fx), fy), fz);
 }
 
+int AGSWaves::ConvertColorToGrayScale(int color) {
+	int r = getRcolor(color);
+	int g = getGcolor(color);
+	int b = getBcolor(color);
+
+	float d = float((r * r + g * g + b * b) / 3);
+	int gr = int(sqrt(d));
+
+	return ((gr << 16) | (gr << 8) | (gr << 0) | (255 << 24));
+}
+
+bool AGSWaves::IsPixelTransparent(int color) {
+	int ad = getAcolor(color);
+	return ad < 255;
+}
+
 } // namespace AGSWaves
 } // namespace Plugins
 } // namespace AGS3
diff --git a/engines/ags/plugins/ags_waves/sound.cpp b/engines/ags/plugins/ags_waves/sound.cpp
new file mode 100644
index 0000000000..224722d4cb
--- /dev/null
+++ b/engines/ags/plugins/ags_waves/sound.cpp
@@ -0,0 +1,89 @@
+/* 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 "common/util.h"
+#include "ags/plugins/ags_waves/ags_waves.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSWaves {
+
+
+void AGSWaves::SFX_Play(ScriptMethodParams &params) {
+	//PARAMS2(int, SFX, int, repeat);
+}
+
+void AGSWaves::SFX_SetVolume(ScriptMethodParams &params) {
+	//PARAMS2(int, SFX, int, volume);
+}
+
+void AGSWaves::SFX_GetVolume(ScriptMethodParams &params) {
+	//PARAMS1(int, SFX);
+	params._result = 0;
+}
+
+void AGSWaves::Music_Play(ScriptMethodParams &params) {
+	//PARAMS6(int, MFX, int, repeat, int, fadeinMS, int, fadeoutMS, int, Position, bool, fixclick);
+}
+
+void AGSWaves::Music_SetVolume(ScriptMethodParams &params) {
+	//PARAMS1(int, volume);
+}
+
+void AGSWaves::Music_GetVolume(ScriptMethodParams &params) {
+	params._result = 0;
+}
+
+void AGSWaves::SFX_Stop(ScriptMethodParams &params) {
+	//PARAMS2(int, SFX, int, fademsOUT);
+}
+
+void AGSWaves::SFX_SetPosition(ScriptMethodParams &params) {
+	//PARAMS4(int, SFX, int, x, int, y, int, intensity);
+}
+
+void AGSWaves::SFX_SetGlobalVolume(ScriptMethodParams &params) {
+	//PARAMS1(int, volume);
+}
+
+void AGSWaves::Load_SFX(ScriptMethodParams &params) {
+	//PARAMS1(int, SFX);
+}
+
+void AGSWaves::Audio_Apply_Filter(ScriptMethodParams &params) {
+	//PARAMS1(int, Frequency);
+}
+
+void AGSWaves::Audio_Remove_Filter(ScriptMethodParams &params) {
+}
+
+void AGSWaves::SFX_AllowOverlap(ScriptMethodParams &params) {
+	//PARAMS2(int, SFX, int, allow);
+}
+
+void AGSWaves::SFX_Filter(ScriptMethodParams &params) {
+	//PARAMS2(int, SFX, int, enable);
+}
+
+} // namespace AGSWaves
+} // namespace Plugins
+} // namespace AGS3
diff --git a/engines/ags/plugins/ags_waves/vars.h b/engines/ags/plugins/ags_waves/vars.h
index 8fced69c75..662076f6fa 100644
--- a/engines/ags/plugins/ags_waves/vars.h
+++ b/engines/ags/plugins/ags_waves/vars.h
@@ -149,8 +149,8 @@ struct Vars {
 	int transp;
 	int life;
 	bool active;
-	int dx;
-	int dy;
+	int _dx;
+	int _dy;
 	int mlay;
 	int timlay;
 	int movedport;
@@ -215,6 +215,12 @@ struct Vars {
 	int dY[30];
 	int tDy[30];
 	int direction[30];
+
+	// Warper fields
+	int _newWidth = 0, _newHeight = 0;
+	int _y2 = 0;
+	int _x3 = 0, _y3 = 0;
+	int _x4 = 0, _y4 = 0;
 };
 
 } // namespace AGSWaves
diff --git a/engines/ags/plugins/ags_waves/warper.cpp b/engines/ags/plugins/ags_waves/warper.cpp
new file mode 100644
index 0000000000..9baf71061d
--- /dev/null
+++ b/engines/ags/plugins/ags_waves/warper.cpp
@@ -0,0 +1,186 @@
+/* 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 "common/util.h"
+#include "ags/plugins/ags_waves/ags_waves.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSWaves {
+
+
+void AGSWaves::ReturnNewHeight(ScriptMethodParams &params) {
+	params._result = _newHeight;
+}
+
+void AGSWaves::ReturnNewWidth(ScriptMethodParams &params) {
+	params._result = _newWidth;
+}
+
+void AGSWaves::Warper(ScriptMethodParams &params) {
+	PARAMS5(int, swarp, int, sadjust, int, x1, int, y1, int, x2);
+
+	ix = 0.0;
+	iy = 0.0;
+	ua = 0.0;
+	// some precautions against non-positive values for width and height
+
+	float ax = float(x1), ay = float(y1);
+	float bx = float(x2), by = float(_y2);
+	float cx = float(_x3), cy = float(_y3);
+	float dx = float(_x4), dy = float(_y4);
+
+	int w = int(max4(ax, bx, cx, dx)) + 1;
+	int h = int(max4(ay, by, cy, dy)) + 1;
+
+	BITMAP *refsrc = _engine->GetSpriteGraphic(swarp);
+	int refsrc_width = 640;
+	int refsrc_height = 360;
+	int refsrc_depth = 32;
+	_engine->GetBitmapDimensions(refsrc, &refsrc_width, &refsrc_height, &refsrc_depth);
+	unsigned int **refsprite_pixels = (unsigned int **)_engine->GetRawBitmapSurface(refsrc);
+	_engine->ReleaseBitmapSurface(refsrc);
+
+
+	// create temporary sprite holding the warped version
+	BITMAP *resizeb = _engine->GetSpriteGraphic(sadjust);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(resizeb, &src_width, &src_height, &src_depth);
+	unsigned int **sprite_pixels = (unsigned int **)_engine->GetRawBitmapSurface(resizeb);
+
+
+	int ow = refsrc_width, oh = refsrc_height;
+
+	int x, y;  // pixel coords
+	float fx, fy; // original sprite's in between pixel coords
+
+	int il;
+
+	// calculate intersections of opposing sides
+	float orx_x, orx_y, ory_x, ory_y;
+	bool xp = false, yp = false; // parallel sides?
+
+	// AC and BD to get intersection of all "vertical lines"
+
+	il = IntersectLines(ax, ay, cx, cy, bx, by, dx, dy);
+	if (il == 0) {
+		// parallel sides, store directional vector
+		orx_x = cx - ax;
+		orx_y = cy - ay;
+		xp = true;
+	} else {
+		// store intersection of sides
+		orx_x = ix;
+		orx_y = iy;
+	}
+	// AB and CD to get intersection of all "horizontal lines"
+	il = IntersectLines(ax, ay, bx, by, cx, cy, dx, dy);
+	if (il == 0) {
+		// parallel sides, store directional vector
+		ory_x = bx - ax;
+		ory_y = by - ay;
+		yp = true;
+	} else {
+		// store intersection of sides
+		ory_x = ix;
+		ory_y = iy;
+	}
+
+	int xm = int(min4(ax, bx, cx, dx)); // x loop starts here
+
+	y = int(min4(ay, by, cy, dy));
+	while (y < h) {
+		x = xm;
+		while (x < w) {
+
+			// calculate original pixel
+
+			// x:
+			if (xp) il = IntersectLines(ax, ay, bx, by, float(x), float(y), float(x) + orx_x, float(y) + orx_y);
+			else il = IntersectLines(ax, ay, bx, by, float(x), float(y), orx_x, orx_y);
+			fx = float(ow - 1) * ua;
+
+			float ux = ua;
+
+			// y:
+			if (yp) il = IntersectLines(ax, ay, cx, cy, float(x), float(y), float(x) + ory_x, float(y) + ory_y);
+			else il = IntersectLines(ax, ay, cx, cy, float(x), float(y), ory_x, ory_y);
+			fy = float(oh - 1) * ua;
+
+			// only draw if within original sprite
+			if (ux >= 0.0 && ux <= 1.0 && ua >= 0.0 && ua <= 1.0) {
+				int refY = (int)CLIP(fy, (float)0.0, float(refsrc_height - 1));
+				int refX = (int)CLIP(fx, (float)0.0, float(refsrc_width - 1));
+
+				int setcolor = refsprite_pixels[refY][refX];
+
+				int setY = (int)CLIP((float)y, (float)0.0, (float)(src_height - 1));
+				int setX = (int)CLIP((float)x, (float)0.0, (float)(src_width - 1));
+
+				sprite_pixels[setY][setX] = setcolor;
+			}
+
+			x++;
+		}
+
+		y++;
+	}
+
+	_newWidth = w;
+	_newHeight = h;
+	_engine->ReleaseBitmapSurface(resizeb);
+}
+
+void AGSWaves::SetWarper(ScriptMethodParams &params) {
+	//PARAMS5(int, y2x, int, x3x, int, y3x, int, x4x, int, y4x);
+}
+
+
+int AGSWaves::IntersectLines(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+	// check a
+	if (x1 == x2 && y1 == y2)
+		return -1;
+	// check b
+	if (x3 == x4 && y3 == y4)
+		return -1;
+	float den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
+	float num12 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
+	float num34 = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
+
+	if (den == 0.0) {  // no intersection
+		if (num12 == 0.0 && num34 == 0.0)
+			return 2;
+		return 0;
+	}
+
+	ua = num12 / den;
+	ix = x1 + ua * (x2 - x1);
+	iy = y1 + ua * (y2 - y1);
+
+	return 1;
+}
+
+} // namespace AGSWaves
+} // namespace Plugins
+} // namespace AGS3


Commit: f5afbc964d2c3daf4f17aea674af184e4d62efbe
    https://github.com/scummvm/scummvm/commit/f5afbc964d2c3daf4f17aea674af184e4d62efbe
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-20T20:25:54-07:00

Commit Message:
AGS: Implemented AGSWaves weather methods

Changed paths:
  A engines/ags/plugins/ags_waves/weather.cpp
    engines/ags/module.mk
    engines/ags/plugins/ags_waves/ags_waves.cpp
    engines/ags/plugins/ags_waves/ags_waves.h
    engines/ags/plugins/ags_waves/sound.cpp
    engines/ags/plugins/ags_waves/vars.h


diff --git a/engines/ags/module.mk b/engines/ags/module.mk
index 5d3c4ef7ac..60ba8f8ca6 100644
--- a/engines/ags/module.mk
+++ b/engines/ags/module.mk
@@ -355,7 +355,8 @@ MODULE_OBJS = \
 	plugins/ags_waves/data.o \
 	plugins/ags_waves/draw.o \
 	plugins/ags_waves/sound.o \
-	plugins/ags_waves/warper.o
+	plugins/ags_waves/warper.o \
+	plugins/ags_waves/weather.o
 
 ifdef ENABLE_AGS_TESTS
 MODULE_OBJS += \
diff --git a/engines/ags/plugins/ags_waves/ags_waves.cpp b/engines/ags/plugins/ags_waves/ags_waves.cpp
index d8ebbf13f2..fec48d1129 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.cpp
+++ b/engines/ags/plugins/ags_waves/ags_waves.cpp
@@ -99,26 +99,6 @@ void AGSWaves::AGS_EngineStartup(IAGSEngine *engine) {
 	SCRIPT_METHOD(SetWalkbehindBaserine, AGSWaves::SetWalkbehindBaserine);
 }
 
-void AGSWaves::FireUpdate(ScriptMethodParams &params) {
-	//PARAMS2(int, getDynamicSprite, bool, Fire2Visible));
-}
-
-void AGSWaves::WindUpdate(ScriptMethodParams &params) {
-	//PARAMS4(int, ForceX, int, ForceY, int, Transparency, int, sprite);
-}
-
-void AGSWaves::SetWindValues(ScriptMethodParams &params) {
-	//PARAMS4(int, w, int, h, int, pr, int, prev);
-}
-
-void AGSWaves::RainUpdate(ScriptMethodParams &params) {
-	//PARAMS7(int, rdensity, int, FX, int, FY, int, RW, int, RH, int, graphic, float, perc);
-}
-
-void AGSWaves::NoiseCreator(ScriptMethodParams &params) {
-	//PARAMS2(int, graphic, int, setA);
-}
-
 void AGSWaves::StartingValues() {
 	GeneralAudio.NumOfChannels = 0;
 	GeneralAudio.Initialized = false;
diff --git a/engines/ags/plugins/ags_waves/ags_waves.h b/engines/ags/plugins/ags_waves/ags_waves.h
index 6f06bd879a..700c5bad76 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.h
+++ b/engines/ags/plugins/ags_waves/ags_waves.h
@@ -132,6 +132,17 @@ private:
 	static float max4(float m1, float m2, float m3, float m4) {
 		return MAX(MAX(m1, m2), MAX(m3, m4));
 	}
+
+	// Weather
+	void DrawLineCustom(int x1, int y1, int x2, int y2, int graphic, int setR, int setG, int setB, int setA, int TranDif);
+	void CreateParticle(int xx, int yy, int ForceX, int ForceY);
+	void CreateParticle2(int xx, int yy, int ForceX, int ForceY);
+	void CreateParticleF(int xx, int yy, int ForceX, int ForceY);
+	void CreateDustParticle(int xx, int yy);
+	void CreateRainParticleMid(int x, int y, int fx, int fy, int maxpart);
+	void CreateRainParticleFore(int x, int y, int fx, int fy, int maxpart);
+	void CreateRainParticleBack(int x, int y, int fx, int fy, int maxpart);
+
 public:
 	AGSWaves() : PluginBase(), Vars() {}
 	virtual ~AGSWaves() {}
diff --git a/engines/ags/plugins/ags_waves/sound.cpp b/engines/ags/plugins/ags_waves/sound.cpp
index 224722d4cb..d573828f8a 100644
--- a/engines/ags/plugins/ags_waves/sound.cpp
+++ b/engines/ags/plugins/ags_waves/sound.cpp
@@ -27,6 +27,9 @@ namespace AGS3 {
 namespace Plugins {
 namespace AGSWaves {
 
+void AGSWaves::NoiseCreator(ScriptMethodParams &params) {
+	//PARAMS2(int, graphic, int, setA);
+}
 
 void AGSWaves::SFX_Play(ScriptMethodParams &params) {
 	//PARAMS2(int, SFX, int, repeat);
diff --git a/engines/ags/plugins/ags_waves/vars.h b/engines/ags/plugins/ags_waves/vars.h
index 662076f6fa..352da1b326 100644
--- a/engines/ags/plugins/ags_waves/vars.h
+++ b/engines/ags/plugins/ags_waves/vars.h
@@ -39,7 +39,29 @@ typedef int SDL_AudioSpec;
 typedef int SDL_AudioDeviceID;
 
 struct Particle {
-	int x, y;
+	int x;
+	int y;
+	int transp;
+	int life;
+	bool active;
+	int dx;
+	int dy;
+	int mlay;
+	int timlay;
+	int movedport;
+	int translay;
+	int translayHold;
+	int width;
+	int height;
+	int fx;
+	int fy;
+	bool doingcircle;
+	float angle;
+	float radius;
+	int doingCircleChance;
+	float angleLay;
+	int frame;
+	float anglespeed;
 };
 
 /*---------------------------------------------*/
@@ -144,30 +166,6 @@ struct Vars {
 	double xvOGG[3];
 	double yvOGG[3];
 
-	int _x;
-	int _y;
-	int transp;
-	int life;
-	bool active;
-	int _dx;
-	int _dy;
-	int mlay;
-	int timlay;
-	int movedport;
-	int translay;
-	int translayHold;
-	int _width;
-	int _height;
-	int _fx;
-	int _fy;
-	bool doingcircle;
-	float _angle;
-	float _radius;
-	int doingCircleChance;
-	float angleLay;
-	int frame;
-	float anglespeed;
-
 	Particle particles[110];
 	Particle particlesF[10];
 	Particle particles2[12];
diff --git a/engines/ags/plugins/ags_waves/weather.cpp b/engines/ags/plugins/ags_waves/weather.cpp
new file mode 100644
index 0000000000..de74fe174f
--- /dev/null
+++ b/engines/ags/plugins/ags_waves/weather.cpp
@@ -0,0 +1,1079 @@
+/* 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_waves/ags_waves.h"
+
+namespace AGS3 {
+namespace Plugins {
+namespace AGSWaves {
+
+void AGSWaves::FireUpdate(ScriptMethodParams &params) {
+	PARAMS2(int, getDynamicSprite, bool, Fire2Visible);
+
+	BITMAP *src = _engine->GetSpriteGraphic(getDynamicSprite);
+	uint32 **pixel_src = (uint32 **)_engine->GetRawBitmapSurface(src);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+
+	//OUTLINE
+	creationdelay += int(2.0);
+	if (creationdelay > 4 && Fire2Visible) {
+		int by = 0;
+		while (by < 6) {
+			int dnx = 95 + (Random(535 - 95));
+			int dny = Random(236);
+
+			PluginMethod sfGetRegionXY = _engine->GetScriptFunctionAddress("GetRegionAt");
+			int getID = sfGetRegionXY(dnx, dny);
+
+			while (getID != 10) {
+				dnx = 95 + (Random(535 - 95));
+				dny = Random(236);
+				getID = sfGetRegionXY(dnx, dny);
+			}
+			CreateDustParticle(dnx, dny);
+			by++;
+		}
+
+		creationdelay = 0;
+	}
+	int h = dsizeDust - 1;
+	while (h > 0) {
+		if (dusts[h].life > 0) {
+			dusts[h].life -= int(2.0);
+
+			int setX = dusts[h].x;
+			int setY = dusts[h].y;
+
+			if (setX < 0) setX = 0;
+			if (setX > src_width) setX = src_width;
+
+			if (setY < 0) setY = 0;
+			if (setY > src_height) setY = src_height;
+
+			int Rf = Random(100);
+			int rv, gv, bv, av;
+
+			if (Rf < 50) {
+				rv = 255; gv = 128; bv = 0;
+			} else {
+				rv = 231; gv = 71; bv = 24;
+			}
+
+			av = int((float(255 * (150 - dusts[h].transp))) / 100.0);
+
+
+			pixel_src[setY][setX] = SetColorRGBA(rv, gv, bv, av);
+
+			//drawt.DrawImage(dusts[h].x, dusts[h].y, sg, dusts[h].transp);
+			dusts[h].timlay += int(8.0);
+			if (dusts[h].timlay > dusts[h].mlay) {
+				dusts[h].timlay = 0;
+				dusts[h].x += dusts[h].dx + Random(1);
+				dusts[h].y += dusts[h].dy - (Random(1));
+			}
+			dusts[h].translay += 2;
+			if (dusts[h].translay >= dusts[h].translayHold) {
+				if (dusts[h].transp <= 99) dusts[h].transp++;
+				else dusts[h].life = 0;
+			}
+		} else {
+			dusts[h].active = false;
+		}
+		h--;
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::WindUpdate(ScriptMethodParams &params) {
+	PARAMS4(int, ForceX, int, ForceY, int, Transparency, int, sprite);
+
+	BITMAP *src = _engine->GetSpriteGraphic(sprite);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int by = 0;
+	while (by < 2) {
+		int dnx = Random(ww + 250) - 250;
+		int dny = Random(hh);
+		CreateParticle(dnx, dny, ForceX, ForceY);
+		by++;
+	}
+
+	int dnx;
+	if (ForceX > 0) dnx = (Random(ww + 250) - 250) - (50 + Random(100));
+	else dnx = Random(ww + 250) - 250;
+	//
+	int dny = Random(hh);
+	CreateParticle2(dnx, dny, ForceX, ForceY);
+
+
+	dnx = -(20 + Random(50));//Random(ww);
+	if (dnx < -160) dnx = -160;
+	if (dnx > ww + 160) dnx = ww + 160;
+
+	dny = Random(hh);
+	CreateParticleF(dnx, dny, ForceX, ForceY);
+
+	int h = dsize - 1;
+
+	if (h < dsizeF - 1) {
+		h = dsizeF - 1;
+	}
+
+	int setByx = 0;
+	if (proom == 3 && prevroom == 14) {
+		setByx = 640;
+	}
+	if (proom == 4 && prevroom == 8) {
+		setByx -= 480;
+	}
+	while (h > 0) {
+		if (particles[h].life > 0) {
+			particles[h].life -= int(3.0);
+			particles[h].doingCircleChance -= 2;
+			int df = 100 - particles[h].transp;
+			df = 10 - (df / 4);
+
+			int pwidth = particles[h].width + df;
+			int pheight = particles[h].height + df;
+
+			int px = particles[h].x - (pwidth / 2);
+			int py = particles[h].y - (pheight / 2);
+			int tp = particles[h].transp + Transparency;
+
+			if (tp > 100) tp = 100;
+
+			int pgraph = 0;
+			int SplitBetweenTwo = Random(100);
+			if (SplitBetweenTwo <= 50) pgraph = 813;
+			else pgraph = 4466;
+
+			if (tp != 100) {
+
+				BITMAP *src2 = _engine->GetSpriteGraphic(pgraph + particles[h].frame);
+
+
+				int src2_width = 640;
+				int src2_height = 360;
+				int src2_depth = 32;
+				_engine->GetBitmapDimensions(src2, &src2_width, &src2_height, &src2_depth);
+				uint32 **sprite_pixels2 = (uint32 **)_engine->GetRawBitmapSurface(src2);
+				_engine->ReleaseBitmapSurface(src2);
+
+				int startx = px + setByx;
+				int endx = px + setByx + src2_width;
+				int starty = py;
+				int endy = py + src2_height;
+
+
+
+				int x, y;
+				int ny = 0;
+				for (y = starty; y < endy; y++) {
+					int nx = 0;
+					for (x = startx; x < endx; x++) {
+						int setX = nx;
+						int setY = ny;
+						if (setX < 0)setX = 0;
+						if (setX > src2_width - 1) setX = src2_width - 1;
+						if (setY < 0) setY = 0;
+						if (setY > src2_height - 1) setY = src2_height - 1;
+
+						int netX = x;
+						int netY = y;
+
+
+						if (netX < 0) netX = 0;
+						if (netX > src_width - 1) netX = src_width - 1;
+						if (netY < 0) netY = 0;
+						if (netY > src_height - 1) netY = src_height - 1;
+
+						int clr = sprite_pixels2[setY][setX];
+						int rv = getRcolor(clr);
+						int gv = getGcolor(clr);
+						int bv = getBcolor(clr);
+						int av = getAcolor(clr);
+
+						av = int(float((av * (100 - tp))) / 100.0);
+
+						sprite_pixels[netY][netX] = SetColorRGBA(rv, gv, bv, av);
+						nx++;
+					}
+					ny++;
+				}
+
+			}
+			particles[h].timlay += int(6.0);
+			if (particles[h].timlay > particles[h].mlay) {
+				particles[h].frame++;
+				if (particles[h].frame > 6) particles[h].frame = 0;
+				particles[h].timlay = 0;
+				particles[h].x += particles[h].dx + particles[h].fx;
+				particles[h].y += particles[h].dy + particles[h].fy;//Random(1);
+			}
+			particles[h].translay += 2;
+			if (particles[h].translay >= particles[h].translayHold) {
+				if (particles[h].transp <= 99) particles[h].transp++;
+				else {
+					particles[h].life = 0;
+				}
+			}
+			if (particles[h].x >= (ww - 90) + setByx || particles[h].x < 90 + setByx) {
+				if (particles[h].transp <= 99)particles[h].transp++;
+				else {
+					particles[h].life = 0;
+				}
+			}
+
+			if (!particles[h].doingcircle && particles[h].angle == 0.0
+				&& particles[h].doingCircleChance <= 0) {
+				particles[h].doingcircle = true;
+			}
+			if (particles[h].doingcircle) {
+				particles[h].angleLay += float(1 + WForceX[h]) * 1.5;
+				if (particles[h].angleLay > 12.0) {
+					particles[h].angleLay = 0.0;
+					particles[h].angle += particles[h].anglespeed;
+					int Y = particles[h].y + int((sin(particles[h].angle) * particles[h].radius));
+					int X = particles[h].x + int((cos(particles[h].angle) * particles[h].radius));
+					particles[h].x = X;
+					particles[h].y = Y;
+				}
+			}
+			particles[h].fx = ForceX;
+			particles[h].fy = ForceY;
+
+		} else {
+			particles[h].active = false;
+		}
+
+
+
+
+
+
+		if (h <= 5 && particlesF[h].life > 0) {
+			int pwidth = particlesF[h].width;
+			int pheight = particlesF[h].height;
+			int px = particlesF[h].x - (pwidth / 2);
+			int py = particlesF[h].y - (pheight / 2);
+			int pgraph = 0;
+			int SplitBetweenTwo = Random(100);
+			if (SplitBetweenTwo <= 50) pgraph = 806;
+			else pgraph = 4459;
+
+			int tp = particlesF[h].transp + Transparency;
+			if (tp > 100) tp = 100;
+
+
+			if (tp != 100) {
+
+				BITMAP *src2 = _engine->GetSpriteGraphic(pgraph + particlesF[h].frame);
+				int src2_width = 640;
+				int src2_height = 360;
+				int src2_depth = 32;
+				_engine->GetBitmapDimensions(src2, &src2_width, &src2_height, &src2_depth);
+				uint32 **sprite_pixels2 = (uint32 **)_engine->GetRawBitmapSurface(src2);
+				_engine->ReleaseBitmapSurface(src2);
+
+				int startx = px + setByx;
+				int endx = px + setByx + src2_width;
+				int starty = py;
+				int endy = py + src2_height;
+
+
+				int x, y;
+				int ny = 0;
+				for (y = starty; y < endy; y++) {
+					int nx = 0;
+					for (x = startx; x < endx; x++) {
+						int setX = nx;
+						int setY = ny;
+						if (setX < 0)setX = 0;
+						if (setX > src2_width - 1) setX = src2_width - 1;
+						if (setY < 0) setY = 0;
+						if (setY > src2_height - 1) setY = src2_height - 1;
+
+						int netX = x;
+						int netY = y;
+
+
+						if (netX < 0) netX = 0;
+						if (netX > src_width - 1) netX = src_width - 1;
+						if (netY < 0) netY = 0;
+						if (netY > src_height - 1) netY = src_height - 1;
+
+						int clr = sprite_pixels2[setY][setX];
+						int rv = getRcolor(clr);
+						int gv = getGcolor(clr);
+						int bv = getBcolor(clr);
+						int av = getAcolor(clr);
+
+						av = int(float((av * (100 - tp))) / 100.0);
+
+						sprite_pixels[netY][netX] = SetColorRGBA(rv, gv, bv, av);
+
+						nx++;
+					}
+					ny++;
+				}
+
+
+
+
+				// drawt.DrawImage(px+setByx, py, , tp, pwidth, pheight);
+			}
+			particlesF[h].timlay += int(6.0);
+			if (particlesF[h].timlay > particlesF[h].mlay) {
+				particlesF[h].frame++;
+				if (particlesF[h].frame > 6)  particlesF[h].frame = 0;
+				particlesF[h].timlay = 0;
+				particlesF[h].x += particlesF[h].dx + ForceX;
+				particlesF[h].y += particlesF[h].dy + ForceY;
+			}
+
+
+			if (particlesF[h].x >= ww - 90 || particlesF[h].x < 90) {
+				particlesF[h].translay += 2;
+				if (particlesF[h].translay >= particlesF[h].translayHold) {
+					if (particlesF[h].transp <= 99) particlesF[h].transp++;
+					else {
+						particlesF[h].life = 0;
+					}
+				}
+			}
+		} else {
+			if (h <= 9)  particlesF[h].active = false;
+		}
+
+
+		//SECOND PARTICLES
+		if (h <= 10) {
+			if (particles2[h].life > 0) {
+				particles2[h].life -= int(3.0);
+				particles2[h].doingCircleChance -= 1;
+				int df = 100 - particles2[h].transp;//45-0
+				df = 10 - (df / 4);//10-0
+
+				int pwidth = particles2[h].width + df;
+				int pheight = particles2[h].height + df;
+
+				int px = particles2[h].x - (pwidth / 2);
+				int py = particles2[h].y - (pheight / 2);
+				int tp = particles2[h].transp + Transparency;
+
+				if (tp > 100) tp = 100;
+
+				int pgraph = 5224;
+
+				if (tp != 100) {
+
+					BITMAP *src2 = _engine->GetSpriteGraphic(pgraph + particles2[h].frame);
+
+
+					int src2_width = 640;
+					int src2_height = 360;
+					int src2_depth = 32;
+					_engine->GetBitmapDimensions(src2, &src2_width, &src2_height, &src2_depth);
+					uint32 **sprite_pixels2 = (uint32 **)_engine->GetRawBitmapSurface(src2);
+					_engine->ReleaseBitmapSurface(src2);
+
+					int startx = px + setByx;
+					int endx = px + setByx + src2_width;
+					int starty = py;
+					int endy = py + src2_height;
+
+
+
+					int x, y;
+					int ny = 0;
+					for (y = starty; y < endy; y++) {
+						int nx = 0;
+						for (x = startx; x < endx; x++) {
+							int setX = nx;
+							int setY = ny;
+							if (setX < 0)setX = 0;
+							if (setX > src2_width - 1) setX = src2_width - 1;
+							if (setY < 0) setY = 0;
+							if (setY > src2_height - 1) setY = src2_height - 1;
+
+							int netX = x;
+							int netY = y;
+
+
+							if (netX < 0) netX = 0;
+							if (netX > src_width - 1) netX = src_width - 1;
+							if (netY < 0) netY = 0;
+							if (netY > src_height - 1) netY = src_height - 1;
+
+							int clr = sprite_pixels2[setY][setX];
+							int rv = getRcolor(clr);
+							int gv = getGcolor(clr);
+							int bv = getBcolor(clr);
+							int av = getAcolor(clr);
+
+							av = int(float((av * (100 - tp))) / 100.0);
+
+							sprite_pixels[netY][netX] = SetColorRGBA(rv, gv, bv, av);
+							nx++;
+						}
+						ny++;
+					}
+
+
+				}
+				particles2[h].timlay += int(6.0);
+				if (particles2[h].timlay > particles2[h].mlay) {
+					particles2[h].frame++;
+					if (particles2[h].frame > 7) particles2[h].frame = 0;
+					particles2[h].timlay = 0;
+					particles2[h].x += particles2[h].dx + particles2[h].fx;
+					particles2[h].y += particles2[h].dy + particles2[h].fy;//Random(1);
+				}
+				particles2[h].translay += 2;
+				if (particles2[h].translay >= particles2[h].translayHold) {
+					if (particles2[h].transp <= 99) particles2[h].transp++;
+					else {
+						particles2[h].life = 0;
+					}
+				}
+				if (particles2[h].x >= (ww - 90) + setByx || particles2[h].x < 90 + setByx) {
+					if (particles2[h].transp <= 99)particles2[h].transp++;
+					else {
+						particles2[h].life = 0;
+					}
+				}
+
+				if (!particles2[h].doingcircle && particles2[h].angle == 0.0
+					&& particles2[h].doingCircleChance <= 0) {
+					particles2[h].doingcircle = true;
+				}
+				if (particles2[h].doingcircle) {
+					particles2[h].angleLay += float((1 + WForceX[h + 200]));
+					if (particles2[h].angleLay > 12.0) {
+						particles2[h].angleLay = 0.0;
+						particles2[h].angle += particles2[h].anglespeed;
+						int Y = particles2[h].y + int((sin(particles2[h].angle) * particles2[h].radius));
+						int X = particles2[h].x + int((cos(particles2[h].angle) * particles2[h].radius));
+						particles2[h].x = X;
+						particles2[h].y = Y;
+					}
+				}
+				particles2[h].fx = int(float(ForceX) * 3.5);
+				particles2[h].fy = int(float(ForceY) * 3.5);
+
+			} else {
+				particles2[h].active = false;
+			}
+		}
+
+		// SECOND PARTICLES
+		h--;
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::SetWindValues(ScriptMethodParams &params) {
+	PARAMS4(int, w, int, h, int, pr, int, prev);
+
+	ww = w;
+	hh = h;
+	proom = pr;
+	prevroom = prev;
+}
+
+void AGSWaves::RainUpdate(ScriptMethodParams &params) {
+	PARAMS7(int, rdensity, int, FX, int, FY, int, RW, int, RH, int, graphic, float, perc);
+
+	bool drawBack = true;
+	bool drawMid = true;
+	bool drawFore = true;
+	int h = 0;
+
+	int cdelay = 0;
+	while (cdelay < rdensity) {
+		if (drawMid) CreateRainParticleMid(Random(640 * 4) - 640, -(20 + Random(50)), FX, FY, int((400.0 * perc) / 100.0));
+		if (drawFore) CreateRainParticleFore(Random(640 * 4) - 640, -(20 + Random(50)), FX, FY, int((40.0 * perc) / 100.0));
+		if (drawBack) {
+			CreateRainParticleBack(Random(640 * 4) - 640, -(20 + Random(50)), FX, FY, int((800.0 * perc) / 100.0));
+			CreateRainParticleBack(Random(640 * 4) - 640, -(20 + Random(50)), FX, FY, int((800.0 * perc) / 100.0));
+		}
+		cdelay++;
+	}
+
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+//	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int rotAngle = 6;
+	int rotTrans = 60 + Random(40 + 60);//Random(103)+122;
+	int rotX = -50;
+	int rotY = 120;
+	int totalTrans = 0;
+
+	int maxPart = 800;
+	if (!drawBack) maxPart = 400;
+	if (!drawMid) maxPart = 400;
+
+	while (h < maxPart) {
+		if (h < 400 && drawMid)RainParticles[h].x = RainParticles[h].x - RW;
+		if (h < 400 && drawFore)RainParticlesFore[h].x = RainParticlesFore[h].x - RW;
+		RainParticlesBack[h].x = RainParticlesBack[h].x - RW;
+
+		h++;
+	}
+
+	h = 0;
+	//BACK
+	while (h < maxPart) {
+		//FORE
+		if (h < 400 && drawFore) {
+			if (RainParticlesFore[h].life > 0 && RainParticlesFore[h].active) {
+				RainParticlesFore[h].life -= 4;
+				RainParticlesFore[h].translay += 2;
+				if (RainParticlesFore[h].translay > RainParticlesFore[h].transhold) {
+					RainParticlesFore[h].translay = 0;
+					RainParticlesFore[h].trans += 2;
+				}
+
+				int setRainTrans = RainParticlesFore[h].trans + 8 + Random(10) + totalTrans;
+				if (setRainTrans > 100) {
+					setRainTrans = 100;
+				}
+
+				if (RainParticlesFore[h].y > RH + 30
+					|| RainParticlesFore[h].trans == 100) {
+					RainParticlesFore[h].active = false;
+				} else {
+					//int thick =3;
+					//DRAW LINE
+					int alpha = int(float((255 * (100 - setRainTrans))) / 100.0);
+
+					int x1 = RainParticlesFore[h].x;
+					int y1 = RainParticlesFore[h].y;
+					int x2 = RainParticlesFore[h].x + (RainParticlesFore[h].fx * 2);
+					int y2 = RainParticlesFore[h].y + (RainParticlesFore[h].fy * 2);
+
+					DrawLineCustom(x1, y1, x2, y2, graphic, 255 - 120, 255 - 120, 255 - 120, alpha - 80, 6);
+					DrawLineCustom(x1 - 1, y1, x2 - 1, y2, graphic, 255 - 120, 255 - 120, 255 - 120, alpha - 80, 6);
+
+					DrawLineCustom((x1 - rotX), y1 - rotY, (x2 - rotX) - rotAngle, y2 - rotY, graphic, 255 - 120, 255 - 120, 255 - 120, (alpha - 80) - rotTrans, 6);
+					DrawLineCustom((x1 - 1) - rotX, y1 - rotY, ((x2 - 1) - rotX) - rotAngle, y2 - rotY, graphic, 255 - 120, 255 - 120, 255 - 120, (alpha - 80) - rotTrans, 6);
+
+					RainParticlesFore[h].x += RainParticlesFore[h].fx;
+					RainParticlesFore[h].y += RainParticlesFore[h].fy;
+				}
+			} else {
+				RainParticlesFore[h].life = 0;
+				RainParticlesFore[h].active = false;
+			}
+		}
+		//FORE
+
+		//MID
+		if (!h && drawMid /* h < drawMid */) {
+			if (RainParticles[h].life > 0 && RainParticles[h].active) {
+				RainParticles[h].life -= 4;
+
+				RainParticles[h].translay += 2;
+				if (RainParticles[h].translay > RainParticles[h].transhold) {
+					RainParticles[h].translay = 0;
+					RainParticles[h].trans += 3;
+				}
+
+
+				int setRainTrans = RainParticles[h].trans + 4 + Random(5) + totalTrans;
+				if (setRainTrans > 100) {
+					setRainTrans = 100;
+				}
+
+				if (RainParticles[h].y > RH + 30
+					|| RainParticles[h].trans == 100) {
+					RainParticles[h].active = false;
+				} else {
+					//int thick=2;
+					//DRAW LINE
+					int alpha = int(float((255 * (100 - setRainTrans))) / 100.0);
+
+					int x1 = RainParticles[h].x;
+					int y1 = RainParticles[h].y;
+					int x2 = RainParticles[h].x + RainParticles[h].fx;
+					int y2 = RainParticles[h].y + RainParticles[h].fy;
+
+					DrawLineCustom(x1, y1, x2, y2, graphic, 255 - 40, 255 - 40, 255 - 40, alpha, 6);
+					DrawLineCustom(x1 - 1, y1, x2 - 1, y2, graphic, 255 - 40, 255 - 40, 255 - 40, alpha, 6);
+
+					DrawLineCustom((x1)-rotX, y1 - rotY, (x2 - rotX) - rotAngle, y2 - rotY, graphic, 255 - 40, 255 - 40, 255 - 40, alpha - rotTrans, 6);
+					DrawLineCustom((x1 - 1) - rotX, y1 - rotY, ((x2 - 1) - rotX) - rotAngle, y2 - rotY, graphic, 255 - 40, 255 - 40, 255 - 40, alpha - rotTrans, 6);
+
+					RainParticles[h].x += RainParticles[h].fx;
+					RainParticles[h].y += RainParticles[h].fy;
+				}
+
+			} else {
+				RainParticles[h].life = 0;
+				RainParticles[h].active = false;
+			}
+		}
+		//MID
+		if (h < 800 && drawBack) {
+			if (RainParticlesBack[h].life > 0 && RainParticlesBack[h].active) {
+				RainParticlesBack[h].life -= 4;
+				RainParticlesBack[h].translay += 2;
+				if (RainParticlesBack[h].translay > RainParticlesBack[h].transhold) {
+					RainParticlesBack[h].translay = 0;
+					RainParticlesBack[h].trans++;
+				}
+
+				int setRainTrans = RainParticlesBack[h].trans + totalTrans;//+8+Random(10);
+				if (setRainTrans > 100) {
+					setRainTrans = 100;
+				}
+
+				if (RainParticlesBack[h].y > RH + 30
+					|| RainParticlesBack[h].trans == 100) {
+					RainParticlesBack[h].active = false;
+				} else {
+					//int thick =1;
+					//DRAW LINE
+					int x1 = RainParticlesBack[h].x;
+					int y1 = RainParticlesBack[h].y;
+					int x2 = RainParticlesBack[h].x + RainParticlesBack[h].fx;
+					int y2 = RainParticlesBack[h].y + RainParticlesBack[h].fy;
+
+					int alpha = int(float((255 * (100 - setRainTrans))) / 100.0);
+					DrawLineCustom(x1, y1, x2, y2, graphic, 255 - 80, 255 - 80, 255 - 80, alpha, 3);
+					DrawLineCustom((x1 - rotX), y1 - rotY, (x2 - rotX) - rotAngle, y2 - rotY, graphic, 255 - 80, 255 - 80, 255 - 80, alpha - rotTrans, 3);
+
+					RainParticlesBack[h].x += RainParticlesBack[h].fx;
+					RainParticlesBack[h].y += RainParticlesBack[h].fy;
+				}
+			} else {
+				RainParticlesBack[h].life = 0;
+				RainParticlesBack[h].active = false;
+			}
+		}
+		h++;
+	}
+
+	// BACK
+	_engine->ReleaseBitmapSurface(src);
+}
+
+
+void AGSWaves::DrawLineCustom(int x1, int y1, int x2, int y2, int graphic, int setR, int setG, int setB, int setA, int TranDif) {
+	int ALine = 0;
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int DiffA = -26;
+
+	int x, y;
+	int xe;
+	int ye;
+	int dx = x2 - x1;
+	int dy = y2 - y1;
+	int dx1 = abs(dx);
+	int dy1 = abs(dy);
+	int px = (2 * dy1) - dx1;
+	int py = (2 * dx1) - dy1;
+	if (dy1 <= dx1) {
+		if (dx >= 0) {
+			x = x1;
+			y = y1;
+			xe = x2;
+		} else {
+			x = x2; y = y2; xe = x1;
+		}
+
+		int xx2 = x - 320;
+		int yy2 = y;
+
+		if (xx2 < 0 || xx2 > src_width - 1 || yy2 > src_height - 1 || yy2 < 0) {
+		} else {
+			sprite_pixels[yy2][xx2] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+		}
+
+		int xx3 = x + 320;
+		int yy3 = y;
+
+		if (xx3 < 0 || xx3 > src_width - 1 || yy3 > src_height - 1 || yy3 < 0) {
+		} else {
+			sprite_pixels[yy3][xx3] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+		}
+
+		int xx = x;
+		int yy = y;
+
+		if (xx < 0 || xx > src_width - 1 || yy > src_height - 1 || yy < 0) {
+		} else {
+			sprite_pixels[yy][xx] = SetColorRGBA(setR, setG, setB, setA + (ALine * TranDif));
+			ALine++;
+		}
+
+		int i = 0;
+		while (x < xe) {
+			x = x + 1;
+			if (px < 0) {
+				px = px + 2 * dy1;
+			} else {
+				if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) {
+					y = y + 1;
+				} else {
+					y = y - 1;
+				}
+				px = px + 2 * (dy1 - dx1);
+			}
+
+			xx2 = x - 320;
+			yy2 = y;
+			if (xx2 < 0 || xx2 > src_width - 1 || yy2 > src_height - 1 || yy2 < 0) {
+			} else {
+				sprite_pixels[yy2][xx2] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+			}
+			xx3 = x + 320;
+			yy3 = y;
+			if (xx3 < 0 || xx3 > src_width - 1 || yy3 > src_height - 1 || yy3 < 0) {
+			} else {
+				sprite_pixels[yy3][xx3] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+			}
+
+			xx = x;
+			yy = y;
+			if (xx < 0 || xx > src_width - 1 || yy > src_height - 1 || yy < 0) {
+			} else {
+				sprite_pixels[yy][xx] = SetColorRGBA(setR, setG, setB, setA + (ALine * TranDif));
+				ALine++;
+			}
+
+			i++;
+		}
+	} else {
+		if (dy >= 0) {
+			x = x1;
+			y = y1;
+			ye = y2 - 1;
+		} else {
+			// Line is drawn top to bottom
+			x = x2;
+			y = y2;
+			ye = y1 - 1;
+		}
+
+		int xx2 = x - 320;
+		int yy2 = y;
+
+		if (xx2 < 0 || xx2 > src_width - 1 || yy2 > src_height - 1 || yy2 < 0) {
+		} else {
+			sprite_pixels[yy2][xx2] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+		}
+
+		int xx3 = x + 320;
+		int yy3 = y;
+
+		if (xx3 < 0 || xx3 > src_width - 1 || yy3 > src_height - 1 || yy3 < 0) {
+		} else {
+			sprite_pixels[yy3][xx3] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+		}
+		int xx = x;
+		int yy = y;
+
+		if (xx < 0 || xx > src_width - 1 || yy > src_height - 1 || yy < 0) {
+		} else {
+			sprite_pixels[yy][xx] = SetColorRGBA(setR, setG, setB, setA + (ALine * TranDif));
+			ALine++;
+		}
+
+		int i = 0;
+		while (y < ye) {
+			y = y + 1;
+			if (py <= 0) {
+				py = py + (2 * dx1);
+			} else {
+				if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) {
+					x = x + 1;
+				} else {
+					x = x - 1;
+				}
+				py = py + 2 * (dx1 - dy1);
+			}
+			xx2 = x - 320;
+			yy2 = y;
+			if (xx2 < 0 || xx2 > src_width - 1 || yy2 > src_height - 1 || yy2 < 0) {
+			} else {
+				sprite_pixels[yy2][xx2] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+			}
+			xx3 = x + 320;
+			yy3 = y;
+			if (xx3 < 0 || xx3 > src_width - 1 || yy3 > src_height - 1 || yy3 < 0) {
+			} else {
+				sprite_pixels[yy3][xx3] = SetColorRGBA(setR, setG, setB, setA + DiffA + (ALine * TranDif));
+			}
+			xx = x;
+			yy = y;
+			if (xx < 0 || xx > src_width - 1 || yy > src_height - 1 || yy < 0) {
+			} else {
+				sprite_pixels[yy][xx] = SetColorRGBA(setR, setG, setB, setA + (ALine * TranDif));
+				ALine++;
+			}
+			i++;
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
+
+void AGSWaves::CreateParticle(int xx, int yy, int ForceX, int ForceY) {
+	int h = 0;
+	bool foundparticle = false;
+	int fid = -1;
+	while (h <= dsize && !foundparticle) {
+		if (particles[h].active == false) {
+			foundparticle = true;
+			fid = h;
+		}
+		h++;
+	}
+
+	if (foundparticle) {
+		int d = fid;
+		particles[d].x = xx;
+		particles[d].y = yy;
+		particles[d].dx = 0;
+		particles[d].dy = 0;
+		particles[d].life = 20000;
+		particles[d].transp = 55 + Random(10);
+		particles[d].active = true;
+		particles[d].mlay = 4 + Random(2);
+		particles[d].timlay = 0;
+		particles[d].translay = 0;
+		particles[d].translayHold = 19 + Random(15);
+		particles[d].width = 2 + Random(2);
+		particles[d].height = particles[d].width;
+		particles[d].fx = 0;
+		particles[d].fy = 0;
+		particles[d].doingcircle = false;
+		particles[d].angle = 0.0;
+		particles[d].radius = 4.0 + float(Random(6));
+		particles[d].doingCircleChance = Random(200);
+		particles[d].angleLay = 0.0;
+		particles[d].frame = 0;
+		particles[d].anglespeed = float(Random(20)) / 100.0;
+		WForceX[d] = ForceX;
+		WForceY[d] = ForceY;
+		if (dsize < (raysize - 1)) dsize++;
+	}
+}
+
+void AGSWaves::CreateParticle2(int xx, int yy, int ForceX, int ForceY) {
+	int h = 0;
+	bool foundparticle = false;
+	int fid = -1;
+	while (h <= dsize2 && !foundparticle) {
+		if (particles2[h].active == false) {
+			foundparticle = true;
+			fid = h;
+		}
+		h++;
+	}
+
+	if (foundparticle) {
+		int d = fid;
+		particles2[d].x = xx;
+		particles2[d].y = yy;
+		particles2[d].dx = 0;
+		particles2[d].dy = 0;
+		particles2[d].life = 20000;
+		particles2[d].transp = 65 + Random(15);
+		particles2[d].active = true;
+		particles2[d].mlay = 4 + Random(2);
+		particles2[d].timlay = 0;
+		particles2[d].translay = 0;
+		particles2[d].translayHold = 19 + Random(15);
+		particles2[d].width = 16;
+		particles2[d].height = particles[d].width;
+		particles2[d].fx = 0;
+		particles2[d].fy = 0;
+		particles2[d].doingcircle = false;
+		particles2[d].angle = 0.0;
+		particles2[d].radius = 4.0 + float(Random(6));
+		particles2[d].doingCircleChance = Random(200);
+		particles2[d].angleLay = 0.0;
+		particles2[d].frame = 0;
+		particles2[d].anglespeed = float(Random(20)) / 100.0;
+		WForceX[d + 200] = ForceX;
+		WForceY[d + 200] = ForceY;
+		if (dsize2 < (raysize2 - 1)) dsize2++;
+	}
+}
+
+void AGSWaves::CreateParticleF(int xx, int yy, int ForceX, int ForceY) {
+	int h = 0;
+	bool foundparticle = false;
+	int fid = -1;
+	while (h <= dsizeF && !foundparticle) {
+		if (particlesF[h].active == false) {
+			foundparticle = true;
+			fid = h;
+		}
+		h++;
+	}
+
+	if (foundparticle) {
+		int d = fid;
+		particlesF[d].x = xx;
+		particlesF[d].y = yy;
+		particlesF[d].dx = (-1) + Random(1);
+		particlesF[d].dy = (-1) + Random(1);
+		particlesF[d].life = 20000;
+		particlesF[d].transp = 45 + Random(10);
+		particlesF[d].active = true;
+		particlesF[d].mlay = 4 + Random(2);
+		particlesF[d].timlay = 0;
+		particlesF[d].translay = 0;
+		particlesF[d].translayHold = 19 + Random(15);
+		particlesF[d].width = 8 + Random(2);
+		particlesF[d].height = particlesF[d].width;
+		particlesF[d].fx = 0;
+		particlesF[d].fy = 0;
+		particlesF[d].doingcircle = false;
+		particlesF[d].angle = 0.0;
+		particlesF[d].radius = 4.0 + float(Random(6));
+		particlesF[d].doingCircleChance = Random(200);
+		particlesF[d].angleLay = 0.0;
+		WForceX[d + 100] = ForceX;
+		WForceY[d + 100] = ForceY;
+		particlesF[d].frame = 0;
+		if (dsizeF < (raysizeF - 1)) dsizeF++;
+
+	}
+}
+
+void AGSWaves::CreateDustParticle(int xx, int yy) {
+	int h = 0;
+	bool founddust = false;
+	int fid = -1;
+	while (h <= dsizeDust && !founddust) {
+		if (dusts[h].active == false) {
+			founddust = true;
+			fid = h;
+		}
+		h++;
+	}
+
+	if (founddust) {
+		int d = fid;
+		dusts[d].x = xx;
+		dusts[d].y = yy;
+		dusts[d].dx = (-1) + Random(1);
+		dusts[d].dy = (-1) + Random(1);
+		dusts[d].life = 20000;
+		dusts[d].transp = 55 + Random(10);
+		dusts[d].active = true;
+		dusts[d].mlay = 4 + Random(2);
+		dusts[d].timlay = 0;
+		dusts[d].translay = 0;
+		dusts[d].translayHold = 19 + Random(15);
+		if (dsizeDust < (raysizeDust - 1)) dsizeDust++;
+	}
+}
+
+void AGSWaves::CreateRainParticleMid(int x, int y, int fx, int fy, int maxpart) {
+	int s = 0;
+
+	while (s < maxpart) {
+		if (!RainParticles[s].active) {
+			RainParticles[s].active = true;
+			RainParticles[s].x = x;
+			RainParticles[s].y = y;
+			RainParticles[s].fx = fx;
+			RainParticles[s].fy = fy;
+			RainParticles[s].life = 2000;
+			RainParticles[s].trans = 70 + Random(25);
+			RainParticles[s].transhold = Random(3);
+			RainParticles[s].translay = 0;
+			return;
+		}
+		s++;
+	}
+}
+
+void AGSWaves::CreateRainParticleFore(int x, int y, int fx, int fy, int maxpart) {
+	int s = 0;
+
+	while (s < maxpart) {
+		if (!RainParticlesFore[s].active) {
+			RainParticlesFore[s].active = true;
+			RainParticlesFore[s].x = x;
+			RainParticlesFore[s].y = y;
+			RainParticlesFore[s].fx = fx;//int(1.5*float(fx));
+			RainParticlesFore[s].fy = fy;//int(1.5*float(fy));
+			RainParticlesFore[s].life = 2000;
+			RainParticlesFore[s].trans = 75 + Random(15);
+			RainParticlesFore[s].transhold = Random(3);
+			RainParticlesFore[s].translay = 0;
+			return;
+		}
+		s++;
+	}
+}
+
+void AGSWaves::CreateRainParticleBack(int x, int y, int fx, int fy, int maxpart) {
+	int s = 0;
+
+	while (s < maxpart) {
+		if (!RainParticlesBack[s].active) {
+			RainParticlesBack[s].active = true;
+			RainParticlesBack[s].x = x;
+			RainParticlesBack[s].y = y;
+			if (fx == 0) fx = 1;
+			if (fy == 0) fy = 1;
+			RainParticlesBack[s].fx = fx / 2;
+			RainParticlesBack[s].fy = fy / 2;
+			RainParticlesBack[s].life = 2000;
+			RainParticlesBack[s].trans = 70 + Random(15);
+			RainParticlesBack[s].transhold = 2 + Random(3);
+			RainParticlesBack[s].translay = 0;
+			return;
+		}
+		s++;
+	}
+}
+
+} // namespace AGSWaves
+} // namespace Plugins
+} // namespace AGS3


Commit: aadd100b9c8752933b07d12479bd2a05d3779c34
    https://github.com/scummvm/scummvm/commit/aadd100b9c8752933b07d12479bd2a05d3779c34
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-20T20:25:54-07:00

Commit Message:
AGS: Implementing AGSWaves sound methods

Changed paths:
    engines/ags/plugins/ags_waves/ags_waves.cpp
    engines/ags/plugins/ags_waves/ags_waves.h
    engines/ags/plugins/ags_waves/draw.cpp
    engines/ags/plugins/ags_waves/sound.cpp
    engines/ags/plugins/ags_waves/vars.h
    engines/ags/plugins/serializer.h


diff --git a/engines/ags/plugins/ags_waves/ags_waves.cpp b/engines/ags/plugins/ags_waves/ags_waves.cpp
index fec48d1129..f7e7463721 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.cpp
+++ b/engines/ags/plugins/ags_waves/ags_waves.cpp
@@ -21,15 +21,16 @@
  */
 
 #include "ags/plugins/ags_waves/ags_waves.h"
+#include "ags/plugins/serializer.h"
+#include "ags/ags.h"
 
 namespace AGS3 {
 namespace Plugins {
 namespace AGSWaves {
 
-const uint32 Magic = 0xACAB0000;
-const uint32 Version = 1;
-const uint32 SaveMagic = Magic + Version;
-const float PI = 3.14159265f;
+AGSWaves::AGSWaves() : PluginBase(), Vars() {
+	_mixer = ::AGS::g_vm->_mixer;
+}
 
 const char *AGSWaves::AGS_GetPluginName() {
 	return "AGS Waves";
@@ -38,14 +39,14 @@ const char *AGSWaves::AGS_GetPluginName() {
 void AGSWaves::AGS_EngineStartup(IAGSEngine *engine) {
 	PluginBase::AGS_EngineStartup(engine);
 
-	if (engine->version < 13)
-		engine->AbortGame("Engine interface is too old, need newer version of AGS.");
+	if (_engine->version < 13)
+		_engine->AbortGame("Engine interface is too old, need newer version of AGS.");
 
 	StartingValues();
 
-	Character_GetX = engine->GetScriptFunctionAddress("Character::get_X");
-	Character_GetY = engine->GetScriptFunctionAddress("Character::get_Y");
-	Character_ID = engine->GetScriptFunctionAddress("Character::ID");
+	Character_GetX = _engine->GetScriptFunctionAddress("Character::get_X");
+	Character_GetY = _engine->GetScriptFunctionAddress("Character::get_Y");
+	Character_ID = _engine->GetScriptFunctionAddress("Character::ID");
 
 	SCRIPT_METHOD(DrawScreenEffect, AGSWaves::DrawScreenEffect);
 	SCRIPT_METHOD(SFX_Play, AGSWaves::SFX_Play);
@@ -99,6 +100,56 @@ void AGSWaves::AGS_EngineStartup(IAGSEngine *engine) {
 	SCRIPT_METHOD(SetWalkbehindBaserine, AGSWaves::SetWalkbehindBaserine);
 }
 
+int64 AGSWaves::AGS_EngineOnEvent(int event, NumberPtr data) {
+	switch (event) {
+	case AGSE_PREGUIDRAW:
+//		Update();
+		break;
+
+	case AGSE_RESTOREGAME: {
+		_mixer->stopAll();
+
+		Serializer s(_engine, data, true);
+		for (int j = 0; j < 500 - 1; ++j) {
+			s.syncAsInt(SFX[j]._repeat);
+			s.syncAsInt(SFX[j]._volume);
+			s.syncAsInt(SFX[j]._playing);
+		}
+		break;
+	}
+
+	case AGSE_SAVEGAME: {
+		Serializer s(_engine, data, true);
+		for (int j = 0; j < 500 - 1; ++j) {
+			s.syncAsInt(SFX[j]._repeat);
+			s.syncAsInt(SFX[j]._volume);
+			s.syncAsInt(SFX[j]._playing);
+		}
+		break;
+	}
+
+	case AGSE_PRESCREENDRAW:
+		// Get screen size once here.
+		_engine->GetScreenDimensions(&screen_width, &screen_height, &screen_color_depth);
+
+		//_engine->UnrequestEventHook(AGSE_SAVEGAME);
+		//_engine->UnrequestEventHook(AGSE_RESTOREGAME);
+		break;
+
+	case AGSE_ENTERROOM:
+		for (int j = 0; j < 500 - 1; ++j) {
+			if (!_mixer->isSoundHandleActive(SFX[j]._soundHandle))
+				UnloadSFX(j);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 void AGSWaves::StartingValues() {
 	GeneralAudio.NumOfChannels = 0;
 	GeneralAudio.Initialized = false;
diff --git a/engines/ags/plugins/ags_waves/ags_waves.h b/engines/ags/plugins/ags_waves/ags_waves.h
index 700c5bad76..a6f359947f 100644
--- a/engines/ags/plugins/ags_waves/ags_waves.h
+++ b/engines/ags/plugins/ags_waves/ags_waves.h
@@ -23,6 +23,7 @@
 #ifndef AGS_PLUGINS_AGS_WAVES_AGS_WAVES_H
 #define AGS_PLUGINS_AGS_WAVES_AGS_WAVES_H
 
+#include "audio/mixer.h"
 #include "ags/plugins/ags_plugin.h"
 #include "ags/plugins/ags_waves/vars.h"
 
@@ -32,6 +33,8 @@ namespace AGSWaves {
 
 class AGSWaves : public PluginBase, public Vars {
 	SCRIPT_HASH(AGSWaves)
+private:
+	Audio::Mixer *_mixer;
 private:
 	void DrawScreenEffect(ScriptMethodParams &params);
 	void SFX_Play(ScriptMethodParams &params);
@@ -86,6 +89,7 @@ private:
 
 private:
 	void StartingValues();
+	void Update();
 
 	void CastWave(int delayMax, int PixelsWide, int n);
 	void DrawEffect(int sprite_a, int sprite_b, int id, int n);
@@ -143,12 +147,38 @@ private:
 	void CreateRainParticleFore(int x, int y, int fx, int fy, int maxpart);
 	void CreateRainParticleBack(int x, int y, int fx, int fy, int maxpart);
 
+	// Sound
+	/**
+	 * Plays a sound from the sounds.sfx in the Sounds/ folder
+	 * @param soundToPlay	The sound to play
+	 * @param repeat		Times to repeat, -1 for indefine
+	 */
+	void PlaySFX(int SoundToPlay, int repeat);
+
+	/**
+	 * Loads a sound file to memory
+	 * @param i		Sound number to load
+	 */
+	void LoadSFX(int i);
+
+	/**
+	 * Unloads a sound file from memory
+	 * @param i		Sound number to unload
+	 */
+	void UnloadSFX(int i);
+
+	void GlitchFix();
+	void ApplyFilter(int SetFrequency);
+	void SetFilterFrequency(int setFrequency);
+	void MusicPlay(int MusicToPlay, int repeat, int fadeinMS, int fadeoutMS, int pos, bool forceplay, bool fixclick);
+
 public:
-	AGSWaves() : PluginBase(), Vars() {}
+	AGSWaves();
 	virtual ~AGSWaves() {}
 
 	const char *AGS_GetPluginName() override;
 	void AGS_EngineStartup(IAGSEngine *engine) override;
+	int64 AGS_EngineOnEvent(int event, NumberPtr data) override;
 };
 
 } // namespace AGSWaves
diff --git a/engines/ags/plugins/ags_waves/draw.cpp b/engines/ags/plugins/ags_waves/draw.cpp
index 400cc9e148..b503b3d906 100644
--- a/engines/ags/plugins/ags_waves/draw.cpp
+++ b/engines/ags/plugins/ags_waves/draw.cpp
@@ -981,6 +981,32 @@ void AGSWaves::OutlineOnly(ScriptMethodParams &params) {
 	_engine->ReleaseBitmapSurface(dst);
 }
 
+void AGSWaves::NoiseCreator(ScriptMethodParams &params) {
+	PARAMS2(int, graphic, int, setA);
+
+	BITMAP *src = _engine->GetSpriteGraphic(graphic);
+	int src_width = 640;
+	int src_height = 360;
+	int src_depth = 32;
+	_engine->GetBitmapDimensions(src, &src_width, &src_height, &src_depth);
+	uint32 **sprite_pixels = (uint32 **)_engine->GetRawBitmapSurface(src);
+
+	int x, y;
+	for (y = 0; y < src_height; y++) {
+		for (x = 0; x < src_width; x++) {
+			//int getColor = sprite_pixels[y][x];
+			int r = Random(256);
+			int g = Random(256);
+			int b = Random(256);
+			int a = setA;
+
+			sprite_pixels[y][x] = SetColorRGBA(r, g, b, a);
+
+		}
+	}
+
+	_engine->ReleaseBitmapSurface(src);
+}
 
 void AGSWaves::CastWave(int delayMax, int PixelsWide, int n) {
 	tDy[n]++;
diff --git a/engines/ags/plugins/ags_waves/sound.cpp b/engines/ags/plugins/ags_waves/sound.cpp
index d573828f8a..e87491dfd4 100644
--- a/engines/ags/plugins/ags_waves/sound.cpp
+++ b/engines/ags/plugins/ags_waves/sound.cpp
@@ -20,6 +20,9 @@
  *
  */
 
+#include "audio/decoders/wave.h"
+#include "common/file.h"
+#include "common/fs.h"
 #include "common/util.h"
 #include "ags/plugins/ags_waves/ags_waves.h"
 
@@ -27,53 +30,149 @@ namespace AGS3 {
 namespace Plugins {
 namespace AGSWaves {
 
-void AGSWaves::NoiseCreator(ScriptMethodParams &params) {
-	//PARAMS2(int, graphic, int, setA);
-}
+const float PI = 3.14159265f;
 
 void AGSWaves::SFX_Play(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, repeat);
+	PARAMS2(int, sfxNum, int, repeat);
+
+	SoundEffect &effect = SFX[sfxNum];
+	if (effect._stream == nullptr) {
+		LoadSFX(sfxNum);
+	}
+
+	Audio::AudioStream *sound = effect._stream;
+	if (sound != nullptr) {
+		effect._volume = 255;
+
+		if (repeat != 1) {
+			assert(repeat != 0);
+			Audio::SeekableAudioStream *sas =
+				dynamic_cast<Audio::SeekableAudioStream *>(sound);
+			assert(sas);
+
+			Audio::LoopingAudioStream *las =
+				new Audio::LoopingAudioStream(sas, repeat, DisposeAfterUse::NO);
+			_mixer->playStream(Audio::Mixer::kSFXSoundType, &effect._soundHandle, las);
+		} else {
+			_mixer->playStream(Audio::Mixer::kSFXSoundType, &effect._soundHandle, sound,
+				-1, effect._volume, 0, DisposeAfterUse::YES);
+		}
+
+		if (OGG_Filter && effect._filter && effect._volume > 1) {
+			warning("TODO: Mix_RegisterEffect(grabChan, LPEffect, NULL, NULL);");
+		}
+
+		effect._repeat = repeat;
+		effect._playing = true;
+	}
 }
 
 void AGSWaves::SFX_SetVolume(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, volume);
+	PARAMS2(int, sfxNum, int, volume);
+
+	SoundEffect &effect = SFX[sfxNum];
+
+	if (effect._stream != nullptr) {
+		_mixer->setChannelVolume(effect._soundHandle, volume);
+		effect._volume = volume;
+	}
 }
 
 void AGSWaves::SFX_GetVolume(ScriptMethodParams &params) {
-	//PARAMS1(int, SFX);
-	params._result = 0;
+	PARAMS1(int, sfxNum);
+
+	SoundEffect &effect = SFX[sfxNum];
+	params._result = effect._stream ? effect._volume : 0;
 }
 
 void AGSWaves::Music_Play(ScriptMethodParams &params) {
-	//PARAMS6(int, MFX, int, repeat, int, fadeinMS, int, fadeoutMS, int, Position, bool, fixclick);
+	PARAMS6(int, MFX, int, repeat, int, fadeinMS, int, fadeoutMS, int, Position, bool, fixclick);
+	MusicPlay(MFX, repeat, fadeinMS, fadeoutMS, Position, false, fixclick);
 }
 
 void AGSWaves::Music_SetVolume(ScriptMethodParams &params) {
-	//PARAMS1(int, volume);
+	PARAMS1(int, volume);
+	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
 }
 
 void AGSWaves::Music_GetVolume(ScriptMethodParams &params) {
-	params._result = 0;
+	params._result = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
 }
 
 void AGSWaves::SFX_Stop(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, fademsOUT);
+	PARAMS1(int, sfxNum); //, int, fademsOUT);
+
+	SoundEffect &effect = SFX[sfxNum];
+
+	if (effect._stream != nullptr) {
+		_mixer->stopHandle(effect._soundHandle);
+		UnloadSFX(sfxNum);
+
+		effect._playing = false;
+		effect._repeat = 0;
+		effect._channel = -2;
+	}
 }
 
 void AGSWaves::SFX_SetPosition(ScriptMethodParams &params) {
-	//PARAMS4(int, SFX, int, x, int, y, int, intensity);
+	PARAMS4(int, sfxNum, int, xS, int, yS, int, intensity);
+
+	SoundEffect &effect = SFX[sfxNum];
+
+	if (effect._stream != nullptr) {
+		if (_mixer->isSoundHandleActive(effect._soundHandle)) {
+			int angle = 0;
+			int dist = 0;
+
+			if (xS != 0 && yS != 0) {
+				int pid = _engine->GetPlayerCharacter();
+				playerCharacter = _engine->GetCharacter(pid);
+
+				int x1 = Character_GetX((intptr_t)playerCharacter);
+				int y1 = Character_GetY((intptr_t)playerCharacter);
+
+				int x2 = xS;
+				int y2 = yS;
+
+				int defx = (x1 - x2) * (x1 - x2);
+				int defy = (y1 - y2) * (y1 - y2);
+
+				float SquareRoot = sqrt(float(defx + defy));
+				dist = int(SquareRoot) - intensity;
+				if (dist > 255) dist = 255;
+				if (dist < 0)  dist = 0;
+
+				float xDiff = float(x2 - x1);
+				float yDiff = float(y2 - y1);
+				float at2 = atan2(yDiff, xDiff);
+
+				float angles = (at2 * 360.0 / PI);
+				angle = int(angles);//%360;
+			}
+
+			// TODO: Change Mix_SetPosition to ScummVM equivalent
+			//Mix_SetPosition(id, angle, dist);
+			(void)angle;
+			(void)dist;
+		}
+	}
 }
 
 void AGSWaves::SFX_SetGlobalVolume(ScriptMethodParams &params) {
-	//PARAMS1(int, volume);
+	PARAMS1(int, volume);
+	_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
 }
 
 void AGSWaves::Load_SFX(ScriptMethodParams &params) {
-	//PARAMS1(int, SFX);
+	PARAMS1(int, sfxNum);
+	LoadSFX(sfxNum);
 }
 
 void AGSWaves::Audio_Apply_Filter(ScriptMethodParams &params) {
-	//PARAMS1(int, Frequency);
+	PARAMS1(int, Frequency);
+
+	GlitchFix();
+	ApplyFilter(Frequency);
 }
 
 void AGSWaves::Audio_Remove_Filter(ScriptMethodParams &params) {
@@ -84,7 +183,91 @@ void AGSWaves::SFX_AllowOverlap(ScriptMethodParams &params) {
 }
 
 void AGSWaves::SFX_Filter(ScriptMethodParams &params) {
-	//PARAMS2(int, SFX, int, enable);
+	PARAMS2(int, sfxNum, int, enable);
+
+	// THIS ENABLES/DISABLES the SFX LOW PASS FILTER,
+	// I think by default all sound effects are affected by low pass, but there are some that i've manually disabled from being affected by it with this command
+	SFX[sfxNum]._filter = enable;
+}
+
+
+void AGSWaves::LoadSFX(int i) {
+	Common::FSNode soundsFolder("sounds");
+	Common::FSNode soundFileNode = soundsFolder.getChild(
+		Common::String::format("sound%d.sfx", i));
+
+	Common::File *soundFile = new Common::File();
+	if (soundFile->open(soundFileNode)) {
+		SFX[i]._stream = Audio::makeWAVStream(soundFile, DisposeAfterUse::YES);
+
+	} else {
+		delete soundFile;
+	}
+}
+
+void AGSWaves::UnloadSFX(int i) {
+	if (SFX[i]._stream != nullptr) {
+		_mixer->stopHandle(SFX[i]._soundHandle);
+		delete SFX[i]._stream;
+		SFX[i]._stream = nullptr;
+	}
+}
+
+void AGSWaves::GlitchFix() {
+	// TODO: Implementation
+}
+
+void AGSWaves::ApplyFilter(int setFrequency) {
+	// THIS TURNS ON THE LOW PASS FILTER
+	OGG_Filter = true;
+	GeneralAudio.FilterFrequency = setFrequency;
+	SetFilterFrequency(setFrequency);
+}
+
+void AGSWaves::SetFilterFrequency(int setFrequency) {
+	// TODO: Implementation
+}
+
+void AGSWaves::MusicPlay(int MusicToPlay, int repeat, int fadeinMS, int fadeoutMS, int pos, bool forceplay, bool fixclick) {
+	if (GeneralAudio.Disabled) {
+		return;
+	}
+
+	bool samefile = currentMusic != MusicToPlay;
+	if (forceplay) samefile = true;
+
+	if (samefile) {
+		currentMusicRepeat = repeat;
+		currentMusicFadein = fadeinMS;
+		currentMusic = MusicToPlay;
+
+		if (!MFXStream.Switch) {
+			MFXStream.Channel = 0;
+
+			warning("TODO: OGGplayMusic(MusicLoads[MusicToPlay].musicPath, 0, repeat, 0, fixclick);");
+			MFXStream.ID = MusicToPlay;
+			MFXStream.FadeTime = (fadeinMS / 1000) * 40;
+			MFXStream.FadeRate = (float)_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType)
+				/ (float)MFXStream.FadeTime;
+			MFXStream.FadeVolume = 0.0;
+			MFXStream.HaltedZero = false;
+			//MusicVolCanBeAdjusted=true;
+		} else {
+			MFXStream.HaltedOne = false;
+			MFXStream.Channel = 1;
+
+			warning("TODO: OGGplayMusic(MusicLoads[MusicToPlay].musicPath, 0, repeat, 1, fixclick);");
+
+			MFXStream.ID = MusicToPlay;
+			MFXStream.FadeTime = (fadeoutMS / 1000) * 40;
+			MFXStream.FadeVolume = 0.0;//float(MusicGetVolume());
+			MFXStream.FadeRate = (float)_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType)
+				/ (float)MFXStream.FadeTime;
+			//MusicVolCanBeAdjusted=false;
+		}
+
+		MFXStream.Switch = !MFXStream.Switch;
+	}
 }
 
 } // namespace AGSWaves
diff --git a/engines/ags/plugins/ags_waves/vars.h b/engines/ags/plugins/ags_waves/vars.h
index 352da1b326..6da288a32c 100644
--- a/engines/ags/plugins/ags_waves/vars.h
+++ b/engines/ags/plugins/ags_waves/vars.h
@@ -23,6 +23,8 @@
 #ifndef AGS_PLUGINS_AGS_WAVES_VARS_H
 #define AGS_PLUGINS_AGS_WAVES_VARS_H
 
+#include "audio/audiostream.h"
+
 namespace AGS3 {
 namespace Plugins {
 namespace AGSWaves {
@@ -75,22 +77,23 @@ struct getMus {
 };
 
 //WAVE SOUNDS FILES
-struct Soundeffect {
-	Mix_Chunk *chunk;
-	int repeat;
-	int volume;
-	int playing;
-	int allow;
-	int channel;
-	int filter;
+struct SoundEffect {
+	Audio::AudioStream *_stream;
+	Audio::SoundHandle _soundHandle;
+	int _repeat;
+	int _volume;
+	bool _playing;
+	int _allow;
+	int _channel;
+	int _filter;
 };
 
 struct Aud {
-	int NumOfChannels;
-	bool Initialized;
-	bool Disabled;
-	int FilterFrequency;
-	int SoundValue;
+	int NumOfChannels = 0;
+	bool Initialized = false;
+	bool Disabled = false;
+	int FilterFrequency = 0;
+	int SoundValue = 0;
 };
 
 struct Mus {
@@ -150,7 +153,7 @@ struct Vars {
 	PluginMethod Character_ID;
 
 	getMus MusicLoads[80];
-	Soundeffect SFX[500];
+	SoundEffect SFX[500];
 	RainParticle RainParticles[400];
 	RainParticle RainParticlesFore[400];
 	RainParticle RainParticlesBack[800];
diff --git a/engines/ags/plugins/serializer.h b/engines/ags/plugins/serializer.h
index 97054c4fa8..14345a04ec 100644
--- a/engines/ags/plugins/serializer.h
+++ b/engines/ags/plugins/serializer.h
@@ -31,66 +31,66 @@ namespace Plugins {
 
 class Serializer {
 private:
-IAGSEngine *_engine;
-long _file;
-bool _isLoading;
-public:
-Serializer(IAGSEngine *engine, long file, bool isLoading) :
-	_engine(engine), _file(file), _isLoading(isLoading) {}
+	IAGSEngine *_engine;
+	long _file;
+	bool _isLoading;
+	public:
+	Serializer(IAGSEngine *engine, long file, bool isLoading) :
+		_engine(engine), _file(file), _isLoading(isLoading) {}
 
-bool isLoading() const {
-	return _isLoading;
-}
-bool isSaving() const {
-	return !_isLoading;
-}
+	bool isLoading() const {
+		return _isLoading;
+	}
+	bool isSaving() const {
+		return !_isLoading;
+	}
 
-template<typename T>
-void syncAsInt(T &value) {
-	byte buf[4];
-	if (_isLoading) {
-		_engine->FRead(buf, 4, _file);
-		value = READ_LE_INT32(buf);
-	} else {
-		WRITE_LE_UINT32(buf, value);
-		_engine->FWrite(buf, 4, _file);
+	template<typename T>
+	void syncAsInt(T &value) {
+		byte buf[4];
+		if (_isLoading) {
+			_engine->FRead(buf, 4, _file);
+			value = READ_LE_INT32(buf);
+		} else {
+			WRITE_LE_UINT32(buf, value);
+			_engine->FWrite(buf, 4, _file);
+		}
 	}
-}
 
-void syncAsBool(bool &value) {
-	if (_isLoading)
-		_engine->FRead(&value, 1, _file);
-	else
-		_engine->FWrite(&value, 1, _file);
-}
+	void syncAsBool(bool &value) {
+		if (_isLoading)
+			_engine->FRead(&value, 1, _file);
+		else
+			_engine->FWrite(&value, 1, _file);
+	}
 
-void syncAsInt8(int8 &value) {
-	if (_isLoading)
-		_engine->FRead(&value, 1, _file);
-	else
-		_engine->FWrite(&value, 1, _file);
-}
+	void syncAsInt8(int8 &value) {
+		if (_isLoading)
+			_engine->FRead(&value, 1, _file);
+		else
+			_engine->FWrite(&value, 1, _file);
+	}
 
-void syncAsByte(byte &value) {
-	if (_isLoading)
-		_engine->FRead(&value, 1, _file);
-	else
-		_engine->FWrite(&value, 1, _file);
-}
+	void syncAsByte(byte &value) {
+		if (_isLoading)
+			_engine->FRead(&value, 1, _file);
+		else
+			_engine->FWrite(&value, 1, _file);
+	}
 
-void syncAsFloat(float &value) {
-	if (_isLoading)
-		_engine->FRead(&value, sizeof(float), _file);
-	else
-		_engine->FWrite(&value, sizeof(float), _file);
-}
+	void syncAsFloat(float &value) {
+		if (_isLoading)
+			_engine->FRead(&value, sizeof(float), _file);
+		else
+			_engine->FWrite(&value, sizeof(float), _file);
+	}
 
-void syncAsDouble(double &value) {
-	if (_isLoading)
-		_engine->FRead(&value, sizeof(double), _file);
-	else
-		_engine->FWrite(&value, sizeof(double), _file);
-}
+	void syncAsDouble(double &value) {
+		if (_isLoading)
+			_engine->FRead(&value, sizeof(double), _file);
+		else
+			_engine->FWrite(&value, sizeof(double), _file);
+	}
 };
 
 } // namespace Plugins


Commit: 6a4062d3fc75e888ba293c860e54b59c3b12f3f3
    https://github.com/scummvm/scummvm/commit/6a4062d3fc75e888ba293c860e54b59c3b12f3f3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2021-07-20T20:25:54-07:00

Commit Message:
AGS: Fix some comments in call_function

Changed paths:
    engines/ags/engine/script/script_runtime.cpp


diff --git a/engines/ags/engine/script/script_runtime.cpp b/engines/ags/engine/script/script_runtime.cpp
index f4e13c8b5e..d7f4c9a89e 100644
--- a/engines/ags/engine/script/script_runtime.cpp
+++ b/engines/ags/engine/script/script_runtime.cpp
@@ -166,7 +166,7 @@ int call_function(const Plugins::PluginMethod &method,
 
 	// AN IMPORTANT NOTE ON PARAMS
 	// The original AGS interpreter did a bunch of dodgy function pointers with
-	// varying numbers of parameters, which were all int64_t. To simply matters
+	// varying numbers of parameters, which were all intptr_t. To simply matters
 	// now that we only supported plugins implemented in code, and not DLLs,
 	// we use a simplified Common::Array containing the parameters and result
 
@@ -183,8 +183,9 @@ int call_function(const Plugins::PluginMethod &method,
 		NumberPtr result = method(params);
 
 		// TODO: Though some script methods return pointers, the call_function only
-		// supports a 32-bit result. In case they're actually used by any game, the
-		// guard below will throw a wobbly if they're more than 32-bits
+		// supports a 32-bit result. To avoid weird problems on 64-bit systems that
+		// produce pointers above 32-bits, detect and throw a wobbly
+		// until such time as it can properly be fixed
 		if (result._ptr > (void *)0xffffffff)
 			error("Uhandled 64-bit pointer result from plugin method call");
 




More information about the Scummvm-git-logs mailing list