shithub: cstory

Download patch

ref: fafce1f4c6c5b53aef944135ac72a8a02ad96702
parent: 79e4e567e92c0d938548c85ee622774b98b6d268
parent: cc3c12d065433e00e8fddd311f7098463633d958
author: Cucky <[email protected]>
date: Wed Jan 30 11:13:58 EST 2019

Merge pull request #32 from Clownacy/master

More NPCs, overhauled graphics system, and fixed audio

--- a/Makefile
+++ b/Makefile
@@ -73,6 +73,7 @@
 	NpcAct120 \
 	NpcAct140 \
 	NpcAct200 \
+	NpcAct260 \
 	NpcAct280 \
 	NpcAct300 \
 	NpcAct340 \
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -64,101 +64,157 @@
 	return true;
 }
 
-bool StartDirectDraw()
+static bool IsEnableBitmap(SDL_RWops *fp)
 {
-	//Create renderer
-	gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
-	return true;
-}
+	char str[16];
+	const char *extra_text = "(C)Pixel";
 
-void EndDirectDraw()
-{
-	//Release all surfaces
-	for (int i = 0; i < SURFACE_ID_MAX; i++)
-	{
-		if (surf[i].texture)
-		{
-			SDL_DestroyTexture(surf[i].texture);
-			surf[i].texture = NULL;
-		}
-	}
+	const size_t len = strlen(extra_text);
+
+	fp->seek(fp, -len, RW_SEEK_END);
+	fp->read(fp, str, 1, len);
+	fp->seek(fp, 0, RW_SEEK_SET);
+	return memcmp(str, extra_text, len) == 0;
 }
 
 void ReleaseSurface(int s)
 {
 	//Release the surface we want to release
-	if (surf[s].texture)
+	if (surf[s].in_use)
 	{
 		SDL_DestroyTexture(surf[s].texture);
-		surf[s].texture = NULL;
+		SDL_FreeSurface(surf[s].surface);
+		surf[s].in_use = false;
 	}
 }
 
-bool MakeSurface(SDL_RWops *fp, int surf_no)
+bool MakeSurface_Generic(int bxsize, int bysize, int surf_no)
 {
-	//Check if surf_no can be used
-	if (surf_no > SURFACE_ID_MAX)
+	bool success = false;
+
+#ifdef FIX_BUGS
+	if (surf_no >= SURFACE_ID_MAX)
+#else
+	if (surf_no > SURFACE_ID_MAX)	// OOPS (should be '>=')
+#endif
 	{
-		printf("Tried to create surface with invalid id %d\n", surf_no);
-		return false;
+		printf("Tried to create drawable surface at invalid slot (%d - maximum is %d)\n", surf_no, SURFACE_ID_MAX);
 	}
-	if (surf[surf_no].texture)
+	else
 	{
-		printf("Tried to create surface at id %d, but there's already a texture there\n", surf_no);
-		return false;
+		if (surf[surf_no].in_use == true)
+		{
+			printf("Tried to create drawable surface at occupied slot (%d)\n", surf_no);
+		}
+		else
+		{
+			//Create surface
+			surf[surf_no].surface = SDL_CreateRGBSurfaceWithFormat(0, bxsize * gWindowScale, bysize * gWindowScale, 0, SDL_PIXELFORMAT_RGBA32);
+
+			if (surf[surf_no].surface == NULL)
+			{
+				printf("Failed to create drawable surface %d (SDL_CreateRGBSurfaceWithFormat)\nSDL Error: %s\n", surf_no, SDL_GetError());
+			}
+			else
+			{
+				surf[surf_no].texture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, bxsize * gWindowScale, bysize * gWindowScale);
+
+				if (surf[surf_no].texture == NULL)
+				{
+					printf("Failed to create drawable surface %d (SDL_CreateTexture)\nSDL Error: %s\n", surf_no, SDL_GetError());
+					SDL_FreeSurface(surf[surf_no].surface);
+				}
+				else
+				{
+					surf[surf_no].in_use = true;
+					success = true;
+				}
+			}
+		}
 	}
-	
-	//Load surface from file
-	SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1);
-	if (!surface)
+
+	return success;
+}
+
+static void FlushSurface(int surf_no)
+{
+	unsigned char *raw_pixels;
+	int pitch;
+	SDL_LockTexture(surf[surf_no].texture, NULL, (void**)&raw_pixels, &pitch);
+
+	unsigned char (*src_pixels)[surf[surf_no].surface->pitch / 4][4] = (unsigned char (*)[surf[surf_no].surface->pitch/ 4][4])surf[surf_no].surface->pixels;
+	unsigned char (*dst_pixels)[pitch / 4][4] = (unsigned char (*)[pitch/ 4][4])raw_pixels;
+
+	for (unsigned int h = 0; h < surf[surf_no].surface->h; ++h)
 	{
-		printf("Couldn't load bitmap for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
-		return false;
+		for (unsigned int w = 0; w < surf[surf_no].surface->w; ++w)
+		{
+			dst_pixels[h][w][0] = src_pixels[h][w][0];
+			dst_pixels[h][w][1] = src_pixels[h][w][1];
+			dst_pixels[h][w][2] = src_pixels[h][w][2];
+
+			if (src_pixels[h][w][0] || src_pixels[h][w][1] || src_pixels[h][w][2])	// Colour-key
+				dst_pixels[h][w][3] = 0xFF;
+			else
+				dst_pixels[h][w][3] = 0;
+		}
 	}
-	
-	//Make sure surface has color key on
-	SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0, 0, 0));
-	
-	//Get texture from surface
-	SDL_Texture *texture = SDL_CreateTextureFromSurface(gRenderer, surface);
-	if (!texture)
+
+	SDL_UnlockTexture(surf[surf_no].texture);
+}
+
+static bool LoadBitmap(SDL_RWops *fp, int surf_no, bool create_surface)
+{
+	bool success = false;
+
+	if (surf_no >= SURFACE_ID_MAX)
 	{
-		printf("Failed to convert SDL_Surface to SDL_Texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
-		return false;
+		printf("Tried to load bitmap at invalid slot (%d - maximum is %d\n", surf_no, SURFACE_ID_MAX);
 	}
-	
-	//Create real texture, and copy loaded texture here (has texture target access)
-	int w, h;
-	SDL_QueryTexture(texture, NULL, NULL, &w, &h);
-
-	SDL_Texture *textureAccessible = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, w * gWindowScale, h * gWindowScale);
-	
-	if (!textureAccessible)
+	else
 	{
-		printf("Failed to create real texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
-		return false;
+		if (create_surface && surf[surf_no].in_use)
+		{
+			printf("Tried to create drawable surface at occupied slot (%d)\n", surf_no);
+		}
+		else
+		{
+			SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1);
+
+			if (surface == NULL)
+			{
+				printf("Couldn't load bitmap for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
+			}
+			else
+			{
+				if (create_surface == false || MakeSurface_Generic(surface->w, surface->h, surf_no))
+				{
+					SDL_Surface *converted_surface = SDL_ConvertSurface(surface, surf[surf_no].surface->format, 0);
+
+					if (converted_surface == NULL)
+					{
+						printf("Couldn't convert bitmap to surface format (surface id %d)\nSDL Error: %s\n", surf_no, SDL_GetError());
+					}
+					else
+					{
+						SDL_Rect dst_rect = {0, 0, converted_surface->w * gWindowScale, converted_surface->h * gWindowScale};
+						SDL_BlitScaled(converted_surface, NULL, surf[surf_no].surface, &dst_rect);
+						SDL_FreeSurface(converted_surface);
+						surf[surf_no].needs_updating = true;
+						printf(" ^ Successfully loaded\n");
+						success = true;
+					}
+				}
+
+				SDL_FreeSurface(surface);
+			}
+		}
 	}
-	
-	SDL_SetTextureBlendMode(textureAccessible, SDL_BLENDMODE_BLEND);
-	
-	SDL_SetRenderTarget(gRenderer, textureAccessible);
-	SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
-	SDL_RenderClear(gRenderer);
-	SDL_RenderCopy(gRenderer, texture, NULL, NULL);
-	SDL_SetRenderTarget(gRenderer, NULL);
-	
-	//Set surface's metadata
-	surf[surf_no].texture = textureAccessible;
-	
-	//Free surface and texture
-	SDL_DestroyTexture(texture);
-	SDL_FreeSurface(surface);
-	
-	printf(" ^ Successfully loaded\n");
-	return true;
+
+	return success;
 }
 
-bool MakeSurface_File(const char *name, int surf_no)
+static bool LoadBitmap_File(const char *name, int surf_no, bool create_surface)
 {
 	char path[PATH_LENGTH];
 	SDL_RWops *fp;
@@ -168,9 +224,16 @@
 	fp = SDL_RWFromFile(path, "rb");
 	if (fp)
 	{
-		printf("Loading surface (as .pbm) from %s for surface id %d\n", path, surf_no);
-		if (MakeSurface(fp, surf_no))
-			return true;
+		if (!IsEnableBitmap(fp))
+		{
+			printf("Tried to load bitmap to surface %d, but it's missing the '(C)Pixel' string\n", surf_no);
+		}
+		else
+		{
+			printf("Loading surface (as .pbm) from %s for surface id %d\n", path, surf_no);
+			if (LoadBitmap(fp, surf_no, create_surface))
+				return true;
+		}
 	}
 	
 	//Attempt to load BMP
@@ -178,9 +241,17 @@
 	fp = SDL_RWFromFile(path, "rb");
 	if (fp)
 	{
-		printf("Loading surface (as .bmp) from %s for surface id %d\n", path, surf_no);
-		if (MakeSurface(fp, surf_no))
-			return true;
+		if (!IsEnableBitmap(fp))
+		{
+			printf("Tried to load bitmap to surface %d, but it's missing the '(C)Pixel' string\n", surf_no);
+		}
+		else
+		{
+
+			printf("Loading surface (as .bmp) from %s for surface id %d\n", path, surf_no);
+			if (LoadBitmap(fp, surf_no, create_surface))
+				return true;
+		}
 	}
 	
 	printf("Failed to open file %s\n", name);
@@ -187,7 +258,7 @@
 	return false;
 }
 
-bool MakeSurface_Resource(const char *res, int surf_no)
+static bool LoadBitmap_Resource(const char *res, int surf_no, bool create_surface)
 {
 	SDL_RWops *fp = FindResource(res);
 	
@@ -194,7 +265,7 @@
 	if (fp)
 	{
 		printf("Loading surface from resource %s for surface id %d\n", res, surf_no);
-		if (MakeSurface(fp, surf_no))
+		if (LoadBitmap(fp, surf_no, create_surface))
 			return true;
 	}
 	
@@ -202,36 +273,26 @@
 	return false;
 }
 
-bool ReloadBitmap_File(const char *name, int surf_no)
+bool MakeSurface_File(const char *name, int surf_no)
 {
-	ReleaseSurface(surf_no);
-	return MakeSurface_File(name, surf_no);
+	return LoadBitmap_File(name, surf_no, true);
 }
 
-bool ReloadBitmap_Resource(const char *res, int surf_no)
+bool MakeSurface_Resource(const char *res, int surf_no)
 {
-	ReleaseSurface(surf_no);
-	return MakeSurface_Resource(res, surf_no);
+	return LoadBitmap_Resource(res, surf_no, true);
 }
 
-bool MakeSurface_Generic(int bxsize, int bysize, int surf_no)
+bool ReloadBitmap_File(const char *name, int surf_no)
 {
-	//Delete old surface
-	ReleaseSurface(surf_no);
-	
-	//Create surface
-	surf[surf_no].texture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, bxsize * gWindowScale, bysize * gWindowScale);
-	
-	if (!surf[surf_no].texture)
-	{
-		printf("Failed to create drawable surface %d\nSDL Error: %s\n", surf_no, SDL_GetError());
-		return false;
-	}
-	
-	SDL_SetTextureBlendMode(surf[surf_no].texture, SDL_BLENDMODE_BLEND);
-	return true;
+	return LoadBitmap_File(name, surf_no, false);
 }
 
+bool ReloadBitmap_Resource(const char *res, int surf_no)
+{
+	return LoadBitmap_Resource(res, surf_no, false);
+}
+
 SDL_Rect RectToSDLRect(RECT *rect)
 {
 	SDL_Rect SDLRect = { rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top};
@@ -246,42 +307,27 @@
 
 	//Get texture of what's currently rendered on screen
 	SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, SDL_PIXELFORMAT_RGBA32);
-	SDL_RenderReadPixels(gRenderer, nullptr, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
+	SDL_RenderReadPixels(gRenderer, NULL, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
 
-	SDL_Texture *screenTexture = SDL_CreateTextureFromSurface(gRenderer, surface);
-
-	//Free surface
-	SDL_FreeSurface(surface);
-	
 	//Get rects
 	SDL_Rect frameRect = RectToSDLRect(rect);
 	frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
-	
-	SDL_Texture *textureAccessible = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, frameRect.w, frameRect.h);
-	
-	if (!textureAccessible)
-	{
-		printf("Failed to create real texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
-		return;
-	}
-	
-	SDL_SetTextureBlendMode(textureAccessible, SDL_BLENDMODE_BLEND);
-	
-	SDL_SetRenderTarget(gRenderer, textureAccessible);
-	SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
-	SDL_RenderClear(gRenderer);
-	SDL_RenderCopy(gRenderer, screenTexture, &frameRect, NULL);
-	SDL_SetRenderTarget(gRenderer, NULL);
-	
-	//Set surface's metadata
-	surf[surf_no].texture = textureAccessible;
-	
-	//Free stuff
-	SDL_DestroyTexture(screenTexture);
+
+	SDL_BlitSurface(surface, &frameRect, surf[surf_no].surface, &frameRect);
+	surf[surf_no].needs_updating = true;
+
+	//Free surface
+	SDL_FreeSurface(surface);
 }
 
-void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transparency
+static void DrawBitmap(RECT *rcView, int x, int y, RECT *rect, int surf_no, bool transparent)
 {
+	if (surf[surf_no].needs_updating)
+	{
+		FlushSurface(surf_no);
+		surf[surf_no].needs_updating = false;
+	}
+
 	//Get SDL_Rects
 	SDL_Rect clipRect = RectToSDLRect(rcView);
 	
@@ -295,6 +341,8 @@
 	clipRect = {clipRect.x * gWindowScale, clipRect.y * gWindowScale, clipRect.w * gWindowScale, clipRect.h * gWindowScale};
 	SDL_RenderSetClipRect(gRenderer, &clipRect);
 	
+	SDL_SetTextureBlendMode(surf[surf_no].texture, transparent ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
+
 	//Draw to screen
 	if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0)
 		printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError());
@@ -303,36 +351,14 @@
 	SDL_RenderSetClipRect(gRenderer, NULL);
 }
 
+void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transparency
+{
+	DrawBitmap(rcView, x, y, rect, surf_no, true);
+}
+
 void PutBitmap4(RECT *rcView, int x, int y, RECT *rect, int surf_no) //No Transparency
 {
-	//Get SDL_Rects
-	SDL_Rect clipRect = RectToSDLRect(rcView);
-	
-	SDL_Rect frameRect = RectToSDLRect(rect);
-	frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
-	
-	//Get dest rect
-	SDL_Rect destRect = {x * gWindowScale, y * gWindowScale, frameRect.w, frameRect.h};
-	
-	//Set cliprect
-	clipRect = {clipRect.x * gWindowScale, clipRect.y * gWindowScale, clipRect.w * gWindowScale, clipRect.h * gWindowScale};
-	SDL_RenderSetClipRect(gRenderer, &clipRect);
-	
-	//Get original drawing colour
-	uint8_t origR, origG, origB, origA;
-	SDL_GetRenderDrawColor(gRenderer, &origR, &origG, &origB, &origA);
-	
-	//Draw black behind texture
-	SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0xFF);
-	SDL_RenderFillRect(gRenderer, &destRect);
-	
-	//Draw texture
-	if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0)
-		printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError());
-	
-	//Restore original colour, and undo cliprect
-	SDL_RenderSetClipRect(gRenderer, NULL);
-	SDL_SetRenderDrawColor(gRenderer, origR, origG, origB, origA);
+	DrawBitmap(rcView, x, y, rect, surf_no, false);
 }
 
 void Surface2Surface(int x, int y, RECT *rect, int to, int from)
@@ -341,22 +367,9 @@
 	SDL_Rect rcSet = {x * gWindowScale, y * gWindowScale, (rect->right - rect->left) * gWindowScale, (rect->bottom - rect->top) * gWindowScale};
 	SDL_Rect frameRect = RectToSDLRect(rect);
 	frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
-	
-	//Target surface
-	if (!surf[to].texture)
-	{
-		printf("Tried to draw to surface %d, which doesn't exist\n", to);
-		return;
-	}
-	
-	SDL_SetRenderTarget(gRenderer, surf[to].texture);
-	
-	//Draw texture
-	if (SDL_RenderCopy(gRenderer, surf[from].texture, &frameRect, &rcSet) < 0)
-		printf("Failed to draw texture %d to %d\nSDL Error: %s\n", from, to, SDL_GetError());
-	
-	//Stop targetting surface
-	SDL_SetRenderTarget(gRenderer, NULL);
+
+	SDL_BlitSurface(surf[from].surface, &frameRect, surf[to].surface, &rcSet);
+	surf[to].needs_updating = true;
 }
 
 void CortBox(RECT *rect, uint32_t col)
@@ -375,27 +388,12 @@
 	//Get rect
 	SDL_Rect destRect = RectToSDLRect(rect);
 	destRect = {destRect.x * gWindowScale, destRect.y * gWindowScale, destRect.w * gWindowScale, destRect.h * gWindowScale};
-	
-	//Target surface
-	if (!surf[surf_no].texture)
-	{
-		printf("Tried to draw a rectangle to surface %d, which doesn't exist\n", surf_no);
-		return;
-	}
-	
-	SDL_SetRenderTarget(gRenderer, surf[surf_no].texture);
-	
+
 	const unsigned char col_red = (col & 0xFF0000) >> 16;
 	const unsigned char col_green = (col & 0x00FF00) >> 8;
 	const unsigned char col_blue = col & 0x0000FF;
-	const unsigned char col_alpha = (col_red || col_green || col_blue) ? 0xFF : 0;
-
-	//Set colour and draw
-	SDL_SetRenderDrawColor(gRenderer, col_red, col_green, col_blue, col_alpha);
-	SDL_RenderFillRect(gRenderer, &destRect);
-	
-	//Stop targetting surface
-	SDL_SetRenderTarget(gRenderer, NULL);
+	SDL_FillRect(surf[surf_no].surface, &destRect, SDL_MapRGB(surf[surf_no].surface->format, col_red, col_green, col_blue));
+	surf[surf_no].needs_updating = true;
 }
 
 #ifdef WINDOWS
@@ -491,12 +489,24 @@
 
 void PutText(int x, int y, const char *text, uint32_t color)
 {
-	DrawText(gFont, gRenderer, NULL, x * gWindowScale, y * gWindowScale, color, text, strlen(text));
+	int surface_width, surface_height;
+	SDL_GetRendererOutputSize(gRenderer, &surface_width, &surface_height);
+
+	SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, surface_width, surface_height, 0, SDL_PIXELFORMAT_RGBA32);
+	SDL_RenderReadPixels(gRenderer, NULL, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
+
+	DrawText(gFont, surface, x * gWindowScale, y * gWindowScale, color, text, strlen(text));
+
+	SDL_Texture *screen_texture = SDL_CreateTextureFromSurface(gRenderer, surface);
+	SDL_FreeSurface(surface);
+	SDL_RenderCopy(gRenderer, screen_texture, NULL, NULL);
+	SDL_DestroyTexture(screen_texture);
 }
 
 void PutText2(int x, int y, const char *text, uint32_t color, int surf_no)
 {
-	DrawText(gFont, gRenderer, surf[surf_no].texture, x * gWindowScale, y * gWindowScale, color, text, strlen(text));
+	DrawText(gFont, surf[surf_no].surface, x * gWindowScale, y * gWindowScale, color, text, strlen(text));
+	surf[surf_no].needs_updating = true;
 }
 
 void EndTextObject()
@@ -504,4 +514,18 @@
 	//Destroy font
 	UnloadFont(gFont);
 	gFont = nullptr;
+}
+
+bool StartDirectDraw()
+{
+	//Create renderer
+	gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
+	return true;
+}
+
+void EndDirectDraw()
+{
+	//Release all surfaces
+	for (int i = 0; i < SURFACE_ID_MAX; i++)
+		ReleaseSurface(i);
 }
--- a/src/Draw.h
+++ b/src/Draw.h
@@ -45,6 +45,9 @@
 
 struct SURFACE
 {
+	bool in_use;
+	bool needs_updating;
+	SDL_Surface *surface;
 	SDL_Texture *texture;
 };
 
--- a/src/Font.cpp
+++ b/src/Font.cpp
@@ -175,20 +175,12 @@
 	return font_object;
 }
 
-void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, unsigned long colour, const char *string, size_t string_length)
+void DrawText(FontObject *font_object, SDL_Surface *surface, int x, int y, unsigned long colour, const char *string, size_t string_length)
 {
 	if (font_object != NULL)
 	{
 		const unsigned char colours[3] = {(unsigned char)(colour >> 16), (unsigned char)(colour >> 8), (unsigned char)colour};
 
-		SDL_Texture *old_render_target = SDL_GetRenderTarget(renderer);
-		SDL_SetRenderTarget(renderer, texture);
-
-		int surface_width, surface_height;
-		SDL_GetRendererOutputSize(renderer, &surface_width, &surface_height);
-
-		SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, surface_width, surface_height, 0, SDL_PIXELFORMAT_RGBA32);
-		SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
 		unsigned char (*surface_buffer)[surface->pitch / 4][4] = (unsigned char (*)[surface->pitch / 4][4])surface->pixels;
 
 		FT_Face face = font_object->face;
@@ -238,11 +230,11 @@
 			const int letter_x = x + pen_x + face->glyph->bitmap_left;
 			const int letter_y = y + ((FT_MulFix(face->ascender, face->size->metrics.y_scale) + (64 - 1)) / 64) - (face->glyph->metrics.horiBearingY / 64);
 
-			for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + converted.rows, surface_height); ++iy)
+			for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + converted.rows, surface->h); ++iy)
 			{
 				if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
 				{
-					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, surface_width); ++ix)
+					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, surface->w); ++ix)
 					{
 						const unsigned char (*font_buffer)[converted.pitch / 3][3] = (unsigned char (*)[converted.pitch / 3][3])converted.buffer;
 
@@ -263,7 +255,7 @@
 				}
 				else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
 				{
-					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface_width); ++ix)
+					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface->w); ++ix)
 					{
 						unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
 
@@ -282,7 +274,7 @@
 				}
 				else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
 				{
-					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface_width); ++ix)
+					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface->w); ++ix)
 					{
 						unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
 
@@ -303,12 +295,6 @@
 
 			pen_x += face->glyph->advance.x / 64;
 		}
-
-		SDL_Texture *screen_texture = SDL_CreateTextureFromSurface(renderer, surface);
-		SDL_FreeSurface(surface);
-		SDL_RenderCopy(renderer, screen_texture, NULL, NULL);
-		SDL_DestroyTexture(screen_texture);
-		SDL_SetRenderTarget(renderer, old_render_target);
 	}
 }
 
--- a/src/Font.h
+++ b/src/Font.h
@@ -8,5 +8,5 @@
 
 FontObject* LoadFontFromData(const unsigned char *data, size_t data_size, unsigned int cell_width, unsigned int cell_height);
 FontObject* LoadFont(const char *font_filename, unsigned int cell_width, unsigned int cell_height);
-void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, unsigned long colour, const char *string, size_t string_length);
+void DrawText(FontObject *font_object, SDL_Surface *surface, int x, int y, unsigned long colour, const char *string, size_t string_length);
 void UnloadFont(FontObject *font_object);
--- a/src/NpcAct.h
+++ b/src/NpcAct.h
@@ -21,9 +21,10 @@
 void ActNpc021(NPCHAR *npc);
 void ActNpc022(NPCHAR *npc);
 void ActNpc023(NPCHAR *npc);
-
+void ActNpc024(NPCHAR *npc);
 void ActNpc025(NPCHAR *npc);
 
+void ActNpc028(NPCHAR *npc);
 void ActNpc029(NPCHAR *npc);
 void ActNpc030(NPCHAR *npc);
 
@@ -32,7 +33,7 @@
 void ActNpc034(NPCHAR *npc);
 
 void ActNpc037(NPCHAR *npc);
-
+void ActNpc038(NPCHAR *npc);
 void ActNpc039(NPCHAR *npc);
 
 void ActNpc042(NPCHAR *npc);
@@ -42,12 +43,14 @@
 
 void ActNpc058(NPCHAR *npc);
 void ActNpc059(NPCHAR *npc);
-
+void ActNpc060(NPCHAR *npc);
+void ActNpc061(NPCHAR *npc);
 void ActNpc062(NPCHAR *npc);
 
 void ActNpc064(NPCHAR *npc);
 void ActNpc065(NPCHAR *npc);
 
+void ActNpc069(NPCHAR *npc);
 void ActNpc070(NPCHAR *npc);
 void ActNpc071(NPCHAR *npc);
 void ActNpc072(NPCHAR *npc);
@@ -58,6 +61,8 @@
 void ActNpc077(NPCHAR *npc);
 void ActNpc078(NPCHAR *npc);
 void ActNpc079(NPCHAR *npc);
+void ActNpc080(NPCHAR *npc);
+void ActNpc081(NPCHAR *npc);
 
 void ActNpc083(NPCHAR *npc);
 void ActNpc084(NPCHAR *npc);
@@ -71,9 +76,13 @@
 
 void ActNpc125(NPCHAR *npc);
 
+void ActNpc145(NPCHAR *npc);
+
 void ActNpc151(NPCHAR *npc);
 
 void ActNpc211(NPCHAR *npc);
+
+void ActNpc278(NPCHAR *npc);
 
 void ActNpc298(NPCHAR *npc);
 void ActNpc299(NPCHAR *npc);
--- a/src/NpcAct020.cpp
+++ b/src/NpcAct020.cpp
@@ -9,6 +9,7 @@
 #include "Back.h"
 #include "Triangle.h"
 #include "Caret.h"
+#include "Frame.h"
 
 //Computer
 void ActNpc020(NPCHAR *npc)
@@ -108,6 +109,184 @@
 	npc->rect = rect[npc->ani_no];
 }
 
+//Power Critter
+void ActNpc024(NPCHAR *npc)
+{
+	RECT rcLeft[6];
+	RECT rcRight[6];
+
+	rcLeft[0] = {0, 0, 24, 24};
+	rcLeft[1] = {24, 0, 48, 24};
+	rcLeft[2] = {48, 0, 72, 24};
+	rcLeft[3] = {72, 0, 96, 24};
+	rcLeft[4] = {96, 0, 120, 24};
+	rcLeft[5] = {120, 0, 144, 24};
+
+	rcRight[0] = {0, 24, 24, 48};
+	rcRight[1] = {24, 24, 48, 48};
+	rcRight[2] = {48, 24, 72, 48};
+	rcRight[3] = {72, 24, 96, 48};
+	rcRight[4] = {96, 24, 120, 48};
+	rcRight[5] = {120, 24, 144, 48};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->y += 0x600;
+			npc->act_no = 1;
+			// Fallthrough
+		case 1:
+			if (npc->act_wait >= 8 && gMC.x > npc->x - 0x10000 && gMC.x < npc->x + 0x10000 && gMC.y > npc->y - 0x10000 && gMC.y < npc->y + 0x6000)
+			{
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+
+				npc->ani_no = 1;
+			}
+			else
+			{
+				if (npc->act_wait < 8)
+					++npc->act_wait;
+
+				npc->ani_no = 0;
+			}
+
+			if (npc->shock)
+			{
+				npc->act_no = 2;
+				npc->ani_no = 0;
+				npc->act_wait = 0;
+			}
+
+			if (npc->act_wait >= 8 && gMC.x > npc->x - 0xC000 && gMC.x < npc->x + 0xC000 && gMC.y > npc->y - 0xC000 && gMC.y < npc->y + 0x6000)
+			{
+				npc->act_no = 2;
+				npc->ani_no = 0;
+				npc->act_wait = 0;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 3;
+				npc->ani_no = 2;
+				npc->ym = -0x5FF;
+				PlaySoundObject(108, 1);
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+
+				if (npc->direct == 0)
+					npc->xm = -0x100;
+				else
+					npc->xm = 0x100;
+			}
+
+			break;
+
+		case 3:
+			if (npc->ym > 0x200)
+			{
+				npc->tgt_y = npc->y;
+				npc->act_no = 4;
+				npc->ani_no = 3;
+				npc->act_wait = 0;
+				npc->act_wait = 0;	// lol duplicate line
+			}
+
+			break;
+
+		case 4:
+			if (gMC.x > npc->x)
+				npc->direct = 2;
+			else
+				npc->direct = 0;
+
+			++npc->act_wait;
+
+			if (npc->flag & 7 || npc->act_wait > 100)
+			{
+				npc->damage = 12;
+				npc->act_no = 5;
+				npc->ani_no = 2;
+				npc->xm /= 2;
+			}
+			else
+			{
+				if (npc->act_wait % 4 == 1)
+					PlaySoundObject(110, 1);
+
+				if (++npc->ani_wait > 0)
+				{
+					npc->ani_wait = 0;
+					++npc->ani_no;
+				}
+
+				if (npc->ani_no > 5)
+					npc->ani_no = 3;
+			}
+
+			break;
+
+		case 5:
+			if (npc->flag & 8)
+			{
+				npc->damage = 2;
+				npc->xm = 0;
+				npc->act_wait = 0;
+				npc->ani_no = 0;
+				npc->act_no = 1;
+				PlaySoundObject(26, 1);
+				SetQuake(30);
+			}
+
+			break;
+	}
+
+	if (npc->act_no == 4)
+	{
+		if (gMC.x > npc->x)
+			npc->xm += 0x20;
+		else
+			npc->xm -= 0x20;
+
+		if (npc->tgt_y < npc->y)
+			npc->ym -= 0x10;
+		else
+			npc->ym += 0x10;
+
+		if (npc->ym > 0x200)
+			npc->ym = 0x200;
+		if (npc->ym < -0x200)
+			npc->ym = -0x200;
+
+		if (npc->xm > 0x200)
+			npc->xm = 0x200;
+		if (npc->xm < -0x200)
+			npc->xm = -0x200;
+	}
+	else
+	{
+		npc->ym += 0x20;
+		if (npc->ym > 0x5FF)
+			npc->ym = 0x5FF;
+	}
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
 // Egg Corridor lift
 void ActNpc025(NPCHAR *npc)
 {
@@ -234,6 +413,186 @@
 	npc->rect = rcLeft[npc->ani_no];
 }
 
+//Flying Critter (Grasstown)
+void ActNpc028(NPCHAR *npc)
+{
+	RECT rcLeft[6];
+	RECT rcRight[6];
+
+	rcLeft[0] = {0, 48, 16, 64};
+	rcLeft[1] = {16, 48, 32, 64};
+	rcLeft[2] = {32, 48, 48, 64};
+	rcLeft[3] = {48, 48, 64, 64};
+	rcLeft[4] = {64, 48, 80, 64};
+	rcLeft[5] = {80, 48, 96, 64};
+
+	rcRight[0] = {0, 64, 16, 80};
+	rcRight[1] = {16, 64, 32, 80};
+	rcRight[2] = {32, 64, 48, 80};
+	rcRight[3] = {48, 64, 64, 80};
+	rcRight[4] = {64, 64, 80, 80};
+	rcRight[5] = {80, 64, 96, 80};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->y += 0x600;
+			npc->act_no = 1;
+			// Fallthrough
+		case 1:
+			if (npc->act_wait >= 8 && gMC.x > npc->x - 0x10000 && gMC.x < npc->x + 0x10000 && gMC.y > npc->y - 0x10000 && gMC.y < npc->y + 0x6000)
+			{
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+
+				npc->ani_no = 1;
+			}
+			else
+			{
+				if (npc->act_wait < 8)
+					++npc->act_wait;
+
+				npc->ani_no = 0;
+			}
+
+			if (npc->shock)
+			{
+				npc->act_no = 2;
+				npc->ani_no = 0;
+				npc->act_wait = 0;
+			}
+
+			if ( npc->act_wait >= 8 && gMC.x > npc->x - 0xC000 && gMC.x < npc->x + 0xC000 && gMC.y > npc->y - 0xC000 && gMC.y < npc->y + 0x6000)
+			{
+				npc->act_no = 2;
+				npc->ani_no = 0;
+				npc->act_wait = 0;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 3;
+				npc->ani_no = 2;
+				npc->ym = -1228;
+				PlaySoundObject(30, 1);
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+
+				if (npc->direct == 0)
+					npc->xm = -0x100;
+				else
+					npc->xm = 0x100;
+			}
+
+			break;
+
+		case 3:
+			if (npc->ym > 0x100)
+			{
+				npc->tgt_y = npc->y;
+				npc->act_no = 4;
+				npc->ani_no = 3;
+				npc->act_wait = 0;
+				npc->act_wait = 0;	// lol duplicate line
+			}
+
+			break;
+
+		case 4:
+			if (gMC.x > npc->x)
+				npc->direct = 2;
+			else
+				npc->direct = 0;
+
+			++npc->act_wait;
+
+			if (npc->flag & 7 || npc->act_wait > 100)
+			{
+				npc->damage = 3;
+				npc->act_no = 5;
+				npc->ani_no = 2;
+				npc->xm /= 2;
+			}
+			else
+			{
+				if (npc->act_wait % 4 == 1)
+					PlaySoundObject(109, 1);
+
+				if (npc->flag & 8)
+					npc->ym = -0x200;
+
+				if (++npc->ani_wait > 0)
+				{
+					npc->ani_wait = 0;
+					++npc->ani_no;
+				}
+
+				if (npc->ani_no > 5)
+					npc->ani_no = 3;
+			}
+
+			break;
+
+		case 5:
+			if (npc->flag & 8)
+			{
+				npc->damage = 2;
+				npc->xm = 0;
+				npc->act_wait = 0;
+				npc->ani_no = 0;
+				npc->act_no = 1;
+				PlaySoundObject(23, 1);
+			}
+
+			break;
+	}
+
+	if (npc->act_no == 4)
+	{
+		if (gMC.x > npc->x)
+			npc->xm += 0x20;
+		else
+			npc->xm -= 0x20;
+
+		if (npc->tgt_y < npc->y)
+			npc->ym -= 0x10;
+		else
+			npc->ym += 0x10;
+
+		if (npc->ym > 0x200)
+			npc->ym = 0x200;
+		if (npc->ym < -0x200)
+			npc->ym = -0x200;
+
+		if (npc->xm > 0x200)
+			npc->xm = 0x200;
+		if (npc->xm < -0x200)
+			npc->xm = -0x200;
+	}
+	else
+	{
+		npc->ym += 0x40;
+		if (npc->ym > 0x5FF)
+			npc->ym = 0x5FF;
+	}
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
 //Cthulhu
 void ActNpc029(NPCHAR *npc)
 {
@@ -381,6 +740,42 @@
 		npc->ani_no = 0;
 
 	npc->rect = rect[npc->ani_no];
+}
+
+//Fireplace
+void ActNpc038(NPCHAR *npc)
+{
+	RECT rect[4];
+
+	rect[0] = {128, 64, 144, 80};
+	rect[1] = {144, 64, 160, 80};
+	rect[2] = {160, 64, 176, 80};
+	rect[3] = {176, 64, 192, 80};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			if (++npc->ani_wait > 3)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 3)
+				npc->ani_no = 0;
+
+			npc->rect = rect[npc->ani_no];
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8);
+			// Fallthrough
+		case 11:
+			npc->rect.left = 0;
+			npc->rect.right = 0;
+			break;
+	}
 }
 
 //Save sign
--- a/src/NpcAct060.cpp
+++ b/src/NpcAct060.cpp
@@ -11,6 +11,408 @@
 #include "Map.h"
 #include "CommonDefines.h"
 
+//Toroko
+void ActNpc060(NPCHAR *npc)
+{
+	RECT rcLeft[8];
+	RECT rcRight[8];
+
+	rcLeft[0] = {0, 64, 16, 80};
+	rcLeft[1] = {16, 64, 32, 80};
+	rcLeft[2] = {32, 64, 48, 80};
+	rcLeft[3] = {16, 64, 32, 80};
+	rcLeft[4] = {48, 64, 64, 80};
+	rcLeft[5] = {16, 64, 32, 80};
+	rcLeft[6] = {112, 64, 128, 80};
+	rcLeft[7] = {128, 64, 144, 80};
+
+	rcRight[0] = {0, 80, 16, 96};
+	rcRight[1] = {16, 80, 32, 96};
+	rcRight[2] = {32, 80, 48, 96};
+	rcRight[3] = {16, 80, 32, 96};
+	rcRight[4] = {48, 80, 64, 96};
+	rcRight[5] = {16, 80, 32, 96};
+	rcRight[6] = {112, 80, 128, 96};
+	rcRight[7] = {128, 80, 144, 96};
+
+	switch ( npc->act_no )
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			npc->xm = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 120) == 10)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			if (npc->x - 0x2000 < gMC.x && npc->x + 0x2000 > gMC.x && npc->y - 0x2000 < gMC.y && npc->y + 0x2000 > gMC.y)
+			{
+				if (npc->x <= gMC.x)
+					npc->direct = 2;
+				else
+					npc->direct = 0;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 3:
+			npc->act_no = 4;
+			npc->ani_no = 1;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 4:
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 4)
+				npc->ani_no = 1;
+
+			if (npc->flag & 1)
+			{
+				npc->direct = 2;
+				npc->xm = 0x200;
+			}
+
+			if (npc->flag & 4)
+			{
+				npc->direct = 0;
+				npc->xm = -0x200;
+			}
+
+			if (npc->direct)
+				npc->xm = 0x400;
+			else
+				npc->xm = -0x400;
+
+			break;
+
+		case 6:
+			npc->act_no = 7;
+			npc->act_wait = 0;
+			npc->ani_no = 1;
+			npc->ani_wait = 0;
+			npc->ym = -0x400;
+			// Fallthrough
+		case 7:
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 4)
+				npc->ani_no = 1;
+
+			if (npc->direct)
+				npc->xm = 0x100;
+			else
+				npc->xm = -0x100;
+
+			if (npc->act_wait++ && npc->flag & 8)
+				npc->act_no = 3;
+
+			break;
+
+		case 8:
+			npc->ani_no = 1;
+			npc->act_wait = 0;
+			npc->act_no = 9;
+			npc->ym = -0x200;
+			// Fallthrough
+		case 9:
+			if (npc->act_wait++ && npc->flag & 8)
+				npc->act_no = 0;
+
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			npc->ani_no = 6;
+			npc->ym = -0x400;
+			PlaySoundObject(50, 1);
+
+			if (npc->direct)
+				npc->xm = 0x100;
+			else
+				npc->xm = -0x100;
+
+			break;
+
+		case 11:
+			if ( npc->act_wait++ && npc->flag & 8 )
+			{
+				npc->act_no = 12;
+				npc->ani_no = 7;
+				npc->bits |= 0x2000;
+			}
+
+			break;
+
+		case 12:
+			npc->xm = 0;
+			break;
+	}
+
+	npc->ym += 0x40;
+
+	if (npc->xm > 0x400)
+		npc->xm = 0x400;
+	if (npc->xm < -0x400)
+		npc->xm = -0x400;
+
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
+//King
+void ActNpc061(NPCHAR *npc)
+{
+	RECT rcLeft[11];
+	RECT rcRight[11];
+
+	rcLeft[0] = {224, 32, 240, 48};
+	rcLeft[1] = {240, 32, 256, 48};
+	rcLeft[2] = {256, 32, 272, 48};
+	rcLeft[3] = {272, 32, 288, 48};
+	rcLeft[4] = {288, 32, 304, 48};
+	rcLeft[5] = {224, 32, 240, 48};
+	rcLeft[6] = {304, 32, 320, 48};
+	rcLeft[7] = {224, 32, 240, 48};
+	rcLeft[8] = {272, 32, 288, 48};
+	rcLeft[9] = {0, 0, 0, 0};
+	rcLeft[10] = {112, 32, 128, 48};
+
+	rcRight[0] = {224, 48, 240, 64};
+	rcRight[1] = {240, 48, 256, 64};
+	rcRight[2] = {256, 48, 272, 64};
+	rcRight[3] = {272, 48, 288, 64};
+	rcRight[4] = {288, 48, 304, 64};
+	rcRight[5] = {224, 48, 240, 64};
+	rcRight[6] = {304, 48, 320, 64};
+	rcRight[7] = {224, 48, 240, 64};
+	rcRight[8] = {272, 48, 288, 64};
+	rcRight[9] = {0, 0, 0, 0};
+	rcRight[10] = {112, 32, 128, 48};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			npc->xm = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 120) == 10)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 5:
+			npc->ani_no = 3;
+			npc->xm = 0;
+			break;
+
+		case 6:
+			npc->act_no = 7;
+			npc->act_wait = 0;
+			npc->ani_wait = 0;
+			npc->ym = -0x400;
+			// Fallthrough
+		case 7:
+			npc->ani_no = 2;
+
+			if (npc->direct)
+				npc->xm = 0x200;
+			else
+				npc->xm = -0x200;
+
+			if (npc->act_wait++ && npc->flag & 8)
+				npc->act_no = 5;
+
+			break;
+		case 8:
+			npc->act_no = 9;
+			npc->ani_no = 4;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 9:
+			if (++npc->ani_wait > 4)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 7)
+				npc->ani_no = 4;
+
+			if (npc->direct)
+				npc->xm = 0x200;
+			else
+				npc->xm = -0x200;
+
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			npc->ani_no = 4;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 11:
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 7)
+				npc->ani_no = 4;
+
+			if (npc->direct)
+				npc->xm = 0x400;
+			else
+				npc->xm = -0x400;
+
+			break;
+
+		case 20:
+			SetNpChar(145, 0, 0, 0, 0, 2, npc, 0x100);
+			npc->ani_no = 0;
+			npc->act_no = 0;
+			break;
+
+		case 30:
+			npc->act_no = 31;
+			npc->act_wait = 0;
+			npc->ani_wait = 0;
+			npc->ym = 0;
+			// Fallthrough
+		case 31:
+			npc->ani_no = 2;
+
+			if (npc->direct)
+				npc->xm = 0x600;
+			else
+				npc->xm = -0x600;
+
+			if (npc->flag & 1)
+			{
+				npc->direct = 2;
+				npc->act_no = 7;
+				npc->act_wait = 0;
+				npc->ani_wait = 0;
+				npc->ym = -0x400;
+				npc->xm = 0x200;
+				PlaySoundObject(71, 1);
+				SetDestroyNpChar(npc->x, npc->y, 0x800, 4);
+			}
+
+			break;
+
+		case 40:
+			npc->act_no = 42;
+			npc->act_wait = 0;
+			npc->ani_no = 8;
+			PlaySoundObject(29, 1);
+			// Fallthrough
+		case 42:
+			if (++npc->ani_no > 9)
+				npc->ani_no = 8;
+
+			if (++npc->act_wait > 100)
+			{
+				for (int i = 0; i < 4; ++i)
+					SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, 0, 0x100);
+
+				npc->act_no = 50;
+				npc->surf = 20;
+				npc->ani_no = 10;
+			}
+
+			break;
+
+		case 60:
+			npc->ani_no = 6;
+			npc->act_no = 61;
+			npc->ym = -0x5FF;
+			npc->xm = 0x400;
+			npc->count2 = 1;
+			break;
+
+		case 61:
+			npc->ym += 0x40;
+
+			if (npc->flag & 8)
+			{
+				npc->act_no = 0;
+				npc->count2 = 0;
+				npc->xm = 0;
+			}
+
+			break;
+	}
+
+	if (npc->act_no < 30 || npc->act_no >= 40)
+	{
+		npc->ym += 0x40;
+
+		if (npc->xm > 0x400)
+			npc->xm = 0x400;
+		if (npc->xm < -0x400)
+			npc->xm = -0x400;
+
+		if (npc->ym > 0x5FF)
+			npc->ym = 0x5FF;
+	}
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
 //Kazuma at computer
 void ActNpc062(NPCHAR *npc)
 {
@@ -256,6 +658,142 @@
 		npc->rect = rect_left[npc->ani_no];
 	else
 		npc->rect = rect_right[npc->ani_no];
+}
+
+//Sparkle
+void ActNpc069(NPCHAR *npc)
+{
+	RECT rcLeft[6];
+	RECT rcRight[6];
+
+	rcLeft[0] = {48, 0, 64, 16};
+	rcLeft[1] = {64, 0, 80, 16};
+	rcLeft[2] = {80, 0, 96, 16};
+	rcLeft[3] = {96, 0, 112, 16};
+	rcLeft[4] = {48, 0, 64, 16};
+	rcLeft[5] = {112, 0, 128, 16};
+
+	rcRight[0] = {48, 16, 64, 32};
+	rcRight[1] = {64, 16, 80, 32};
+	rcRight[2] = {80, 16, 96, 32};
+	rcRight[3] = {96, 16, 112, 32};
+	rcRight[4] = {48, 16, 64, 32};
+	rcRight[5] = {112, 16, 128, 32};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			npc->xm = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 100) == 1)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+			else
+			{
+				if (Random(0, 150) == 1)
+				{
+					if (npc->direct == 0)
+						npc->direct = 2;
+					else
+						npc->direct = 0;
+				}
+
+				if (Random(0, 150) == 1)
+				{
+					npc->act_no = 3;
+					npc->act_wait = 50;
+					npc->ani_no = 0;
+				}
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 3:
+			npc->act_no = 4;
+			npc->ani_no = 2;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 4:
+			if (--npc->act_wait == 0)
+				npc->act_no = 0;
+
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 4)
+				npc->ani_no = 2;
+
+			if (npc->flag & 1)
+			{
+				npc->direct = 2;
+				npc->xm = 0x200;
+			}
+
+			if (npc->flag & 4)
+			{
+				npc->direct = 0;
+				npc->xm = -0x200;
+			}
+
+			if (npc->direct == 0)
+				npc->xm = -0x100u;
+			else
+				npc->xm = 0x100;
+
+			break;
+
+		case 5:
+			if (npc->flag & 8)
+				npc->act_no = 0;
+
+			break;
+	}
+
+	switch (npc->act_no)
+	{
+		case 1:
+		case 2:
+		case 4:
+			if (npc->shock)
+			{
+				npc->ym = -0x200;
+				npc->ani_no = 5;
+				npc->act_no = 5;
+			}
+
+			break;
+	}
+
+	npc->ym += 0x40;
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
 }
 
 //Sparkle
--- a/src/NpcAct080.cpp
+++ b/src/NpcAct080.cpp
@@ -10,6 +10,298 @@
 #include "Triangle.h"
 #include "Caret.h"
 
+//Gravekeeper
+void ActNpc080(NPCHAR *npc)
+{
+	RECT rcLeft[7];
+	RECT rcRight[7];
+
+	rcLeft[0] = {0, 64, 24, 88};
+	rcLeft[1] = {24, 64, 48, 88};
+	rcLeft[2] = {0, 64, 24, 88};
+	rcLeft[3] = {48, 64, 72, 88};
+	rcLeft[4] = {72, 64, 96, 88};
+	rcLeft[5] = {96, 64, 120, 88};
+	rcLeft[6] = {120, 64, 144, 88};
+
+	rcRight[0] = {0, 88, 24, 112};
+	rcRight[1] = {24, 88, 48, 112};
+	rcRight[2] = {0, 88, 24, 112};
+	rcRight[3] = {48, 88, 72, 112};
+	rcRight[4] = {72, 88, 96, 112};
+	rcRight[5] = {96, 88, 120, 112};
+	rcRight[6] = {120, 88, 144, 112};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->bits &= ~0x20;
+			npc->act_no = 1;
+			npc->damage = 0;
+			npc->hit.front = 0x800;
+			// Fallthrough
+		case 1:
+			npc->ani_no = 0;
+
+			if (npc->x - 0x10000 < gMC.x && npc->x + 0x10000 > gMC.x && npc->y - 0x6000 < gMC.y && npc->y + 0x4000 > gMC.y)
+			{
+				npc->ani_wait = 0;
+				npc->act_no = 2;
+			}
+
+			if (npc->shock)
+			{
+				npc->ani_no = 1;
+				npc->ani_wait = 0;
+				npc->act_no = 2;
+				npc->bits &= ~0x20u;
+			}
+
+			if (gMC.x >= npc->x)
+				npc->direct = 2;
+			else
+				npc->direct = 0;
+
+			break;
+
+		case 2:
+			if (++npc->ani_wait > 6)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 3)
+				npc->ani_no = 0;
+
+			if (npc->x - 0x2000 < gMC.x && npc->x + 0x2000 > gMC.x)
+			{
+				npc->hit.front = 0x2400;
+				npc->act_wait = 0;
+				npc->act_no = 3;
+				npc->bits |= 0x20;
+				PlaySoundObject(34, 1);
+
+				if (npc->direct == 0)
+					npc->xm = -0x400;
+				else
+					npc->xm = 0x400;
+			}
+
+			if (gMC.x >= npc->x)
+			{
+				npc->direct = 2;
+				npc->xm = 0x100;
+			}
+			else
+			{
+				npc->direct = 0;
+				npc->xm = -0x100;
+			}
+
+			break;
+
+		case 3:
+			npc->xm = 0;
+
+			if (++npc->act_wait > 40)
+			{
+				npc->act_wait = 0;
+				npc->act_no = 4;
+				PlaySoundObject(106, 1);
+			}
+
+			npc->ani_no = 4;
+			break;
+
+		case 4:
+			npc->damage = 10;
+
+			if (++npc->act_wait > 2)
+			{
+				npc->act_wait = 0;
+				npc->act_no = 5;
+			}
+
+			npc->ani_no = 5;
+			break;
+
+		case 5:
+			npc->ani_no = 6;
+
+			if (++npc->act_wait > 60)
+				npc->act_no = 0;
+
+			break;
+	}
+
+	if (npc->xm < 0 && npc->flag & 1)
+		npc->xm = 0;
+	if (npc->xm > 0 && npc->flag & 4)
+		npc->xm = 0;
+
+	npc->ym += 0x20;
+
+	if (npc->xm > 0x400)
+		npc->xm = 0x400;
+	if (npc->xm < -0x400)
+		npc->xm = -0x400;
+
+	if (npc->ym > 0x5FF)
+		npc->xm = 0x5FF;
+	if (npc->ym < -0x5FF)
+		npc->xm = -0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
+//Giant pignon
+void ActNpc081(NPCHAR *npc)
+{
+	RECT rcLeft[6];
+	RECT rcRight[6];
+
+	rcLeft[0] = {144, 64, 168, 88};
+	rcLeft[1] = {168, 64, 192, 88};
+	rcLeft[2] = {192, 64, 216, 88};
+	rcLeft[3] = {216, 64, 240, 88};
+	rcLeft[4] = {144, 64, 168, 88};
+	rcLeft[5] = {240, 64, 264, 88};
+
+	rcRight[0] = {144, 88, 168, 112};
+	rcRight[1] = {168, 88, 192, 112};
+	rcRight[2] = {192, 88, 216, 112};
+	rcRight[3] = {216, 88, 240, 112};
+	rcRight[4] = {144, 88, 168, 112};
+	rcRight[5] = {240, 88, 264, 112};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			npc->xm = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 100) == 1)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+			else
+			{
+				if (Random(0, 150) == 1)
+				{
+					if (npc->direct == 0)
+						npc->direct = 2;
+					else
+						npc->direct = 0;
+				}
+
+				if (Random(0, 150) == 1)
+				{
+					npc->act_no = 3;
+					npc->act_wait = 50;
+					npc->ani_no = 0;
+				}
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 3:
+			npc->act_no = 4;
+			npc->ani_no = 2;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 4:
+			if (--npc->act_wait == 0)
+				npc->act_no = 0;
+
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 4)
+				npc->ani_no = 2;
+
+			if (npc->flag & 1)
+			{
+				npc->direct = 2;
+				npc->xm = 0x200;
+			}
+
+			if (npc->flag & 4)
+			{
+				npc->direct = 0;
+				npc->xm = -0x200;
+			}
+
+			if (npc->direct == 0)
+				npc->xm = -0x100;
+			else
+				npc->xm = 0x100;
+
+			break;
+
+		case 5:
+			if (npc->flag & 8)
+				npc->act_no = 0;
+
+			break;
+	}
+
+	switch (npc->act_no)
+	{
+		case 1:
+		case 2:
+		case 4:
+			if (npc->shock )
+			{
+				npc->ym = -0x200;
+				npc->ani_no = 5;
+				npc->act_no = 5;
+
+				if (npc->x >= gMC.x)
+					npc->xm = -0x100;
+				else
+					npc->xm = 0x100;
+			}
+
+			break;
+	}
+
+	npc->ym += 0x40;
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
 //Igor (cutscene)
 void ActNpc083(NPCHAR *npc)
 {
--- a/src/NpcAct140.cpp
+++ b/src/NpcAct140.cpp
@@ -9,6 +9,46 @@
 #include "Back.h"
 #include "Triangle.h"
 
+//King's sword
+void ActNpc145(NPCHAR *npc)
+{
+	RECT rcLeft[1];
+	RECT rcRight[1];
+
+	rcLeft[0] = {96, 32, 112, 48};
+	rcRight[0] = {112, 32, 128, 48};
+
+	if (npc->act_no == 0)
+	{
+		if (npc->pNpc->count2 == 0)
+		{
+			if (npc->pNpc->direct == 0)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+		}
+		else
+		{
+			if (npc->pNpc->direct == 0)
+				npc->direct = 2;
+			else
+				npc->direct = 0;
+		}
+
+		if (npc->direct == 0)
+			npc->x = npc->pNpc->x - 0x1400;
+		else
+			npc->x = npc->pNpc->x + 0x1400;
+
+		npc->y = npc->pNpc->y;
+	}
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
 //Blue robot (standing)
 void ActNpc151(NPCHAR *npc)
 {
--- /dev/null
+++ b/src/NpcAct260.cpp
@@ -1,0 +1,122 @@
+#include "WindowsWrapper.h"
+
+#include "NpcAct.h"
+
+#include "MyChar.h"
+#include "NpChar.h"
+#include "Game.h"
+#include "Sound.h"
+#include "Back.h"
+#include "Triangle.h"
+
+//Little family
+void ActNpc278(NPCHAR *npc)
+{
+	RECT rcMama[2];
+	RECT rcPapa[2];
+	RECT rcKodomo[2];
+
+	rcPapa[0] = {0, 120, 8, 128};
+	rcPapa[1] = {8, 120, 16, 128};
+
+	rcMama[0] = {16, 120, 24, 128};
+	rcMama[1] = {24, 120, 32, 128};
+
+	rcKodomo[0] = {32, 120, 40, 128};
+	rcKodomo[1] = {40, 120, 48, 128};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			npc->xm = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 60) == 1)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			if (Random(0, 60) == 1)
+			{
+				npc->act_no = 10;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 8)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			npc->act_wait = Random(0, 16);
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+
+			if (Random(0, 9) % 2)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			// Fallthrough
+		case 11:
+			if (npc->direct == 0 && (npc->flag & 1))
+				npc->direct = 2;
+			else if ( npc->direct == 2 && npc->flag & 4 )
+				npc->direct = 0;
+
+			if (npc->direct == 0)
+				npc->xm = -0x100;
+			else
+				npc->xm = 0x100;
+
+			if (++npc->ani_wait > 4)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 1)
+				npc->ani_no = 0;
+
+			if (++npc->act_wait > 0x20)
+				npc->act_no = 0;
+
+			break;
+	}
+
+	npc->ym += 0x20;
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	
+	switch (npc->code_event)
+	{
+		case 200:
+			npc->rect = rcPapa[npc->ani_no];
+			break;
+
+		case 210:
+			npc->rect = rcMama[npc->ani_no];
+			break;
+
+		default:
+			npc->rect = rcKodomo[npc->ani_no];
+			break;
+	}
+}
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -80,11 +80,11 @@
 	ActNpc021,
 	ActNpc022,
 	ActNpc023,
-	nullptr,
+	ActNpc024,
 	ActNpc025,
 	nullptr,
 	nullptr,
-	nullptr,
+	ActNpc028,
 	ActNpc029,
 	ActNpc030,
 	nullptr,
@@ -94,7 +94,7 @@
 	nullptr,
 	nullptr,
 	ActNpc037,
-	nullptr,
+	ActNpc038,
 	ActNpc039,
 	nullptr,
 	nullptr,
@@ -116,8 +116,8 @@
 	nullptr,
 	ActNpc058,
 	ActNpc059,
-	nullptr,
-	nullptr,
+	ActNpc060,
+	ActNpc061,
 	ActNpc062,
 	nullptr,
 	ActNpc064,
@@ -125,7 +125,7 @@
 	nullptr,
 	nullptr,
 	nullptr,
-	nullptr,
+	ActNpc069,
 	ActNpc070,
 	ActNpc071,
 	ActNpc072,
@@ -136,9 +136,9 @@
 	ActNpc077,
 	ActNpc078,
 	ActNpc079,
+	ActNpc080,
+	ActNpc081,
 	nullptr,
-	nullptr,
-	nullptr,
 	ActNpc083,
 	ActNpc084,
 	ActNpc085,
@@ -201,12 +201,12 @@
 	nullptr,
 	nullptr,
 	nullptr,
+	ActNpc145,
 	nullptr,
 	nullptr,
 	nullptr,
 	nullptr,
 	nullptr,
-	nullptr,
 	ActNpc151,
 	nullptr,
 	nullptr,
@@ -334,7 +334,7 @@
 	nullptr,
 	nullptr,
 	nullptr,
-	nullptr,
+	ActNpc278,
 	nullptr,
 	nullptr,
 	nullptr,
--- a/src/Sound.cpp
+++ b/src/Sound.cpp
@@ -129,7 +129,7 @@
 {
 	//Volume is in hundredths of decibels, from 0 to -10000
 	lVolume = clamp(lVolume, (decltype(lVolume))-10000, (decltype(lVolume))0);
-	return pow(10.0f, lVolume / 2000.0f);
+	return pow(10.0, lVolume / 2000.0);
 }
 
 void SOUNDBUFFER::SetVolume(int32_t lVolume)
@@ -174,7 +174,7 @@
 	SDL_UnlockAudioDevice(audioDevice);
 }
 
-void SOUNDBUFFER::Mix(float *buffer, int len)
+void SOUNDBUFFER::Mix(float (*buffer)[2], size_t samples)
 {
 	if (this == NULL)
 		return;
@@ -181,29 +181,25 @@
 	
 	if (!playing) //This sound buffer isn't playing
 		return;
-	
-	size_t samples = len / (sizeof(float) * 2);
-	
+
 	for (size_t sample = 0; sample < samples; sample++)
 	{
-		double freqPosition = (frequency / (double)FREQUENCY); //This is added to position at the end
+		const double freqPosition = frequency / FREQUENCY; //This is added to position at the end
 		
 		//Get the in-between sample this is (linear interpolation)
-		uint8_t sample1 = ((looped || ((size_t)samplePosition) >= 1) ? data[(size_t)samplePosition] : 0x80);
-		uint8_t sample2 = 0x80;
-		if (looping || (((size_t)samplePosition) + 1) < size)
-			sample2 = data[(((size_t)samplePosition) + 1) % size];
+		const float sample1 = ((looped || ((size_t)samplePosition) >= 1) ? data[(size_t)samplePosition] : 0x80);
+		const float sample2 = ((looping || (((size_t)samplePosition) + 1) < size) ? data[(((size_t)samplePosition) + 1) % size] : 0x80);
 		
 		//Interpolate sample
-		float subPos = std::fmod(samplePosition, 1.0);
-		float sampleA = (float)sample1 + ((float)sample2 - (float)sample1) * subPos;
+		const float subPos = std::fmod(samplePosition, 1.0);
+		const float sampleA = sample1 + (sample2 - sample1) * subPos;
 		
 		//Convert sample to float32
-		float sampleConvert = (sampleA - 128.0) / 256.0;
+		const float sampleConvert = (sampleA - 128.0f) / 128.0f;
 		
 		//Mix
-		buffer[sample * 2] += sampleConvert * volume * volume_l;
-		buffer[sample * 2 + 1] += sampleConvert * volume * volume_r;
+		buffer[sample][0] += sampleConvert * volume * volume_l;
+		buffer[sample][1] += sampleConvert * volume * volume_r;
 		
 		//Increment position
 		samplePosition += freqPosition;
@@ -229,14 +225,19 @@
 //Sound mixer
 void AudioCallback(void *userdata, uint8_t *stream, int len)
 {
+	float (*buffer)[2] = (float(*)[2])stream;
+	const size_t samples = len / (sizeof(float) * 2);
+
 	//Clear stream
-	memset(stream, 0, len);
+	for (size_t sample = 0; sample < samples; ++sample)
+	{
+		buffer[sample][0] = 0.0f;
+		buffer[sample][1] = 0.0f;
+	}
 	
 	//Mix sounds to primary buffer
 	for (SOUNDBUFFER *sound = soundBuffers; sound != nullptr; sound = sound->next)
-	{
-		sound->Mix((float*)stream, len);
-	}
+		sound->Mix(buffer, samples);
 }
 
 //Sound things
--- a/src/Sound.h
+++ b/src/Sound.h
@@ -20,7 +20,7 @@
 		void Play(bool bLooping);
 		void Stop();
 		
-		void Mix(float *buffer, int len);
+		void Mix(float (*buffer)[2], size_t samples);
 		
 		SOUNDBUFFER *next;