diff --git a/Makefile b/Makefile index fc8a1d64..ddeef95b 100644 --- a/Makefile +++ b/Makefile @@ -73,6 +73,7 @@ SOURCES = \ NpcAct120 \ NpcAct140 \ NpcAct200 \ + NpcAct260 \ NpcAct280 \ NpcAct300 \ NpcAct340 \ diff --git a/src/Draw.cpp b/src/Draw.cpp index 77ef3d0a..cf8fee50 100644 --- a/src/Draw.cpp +++ b/src/Draw.cpp @@ -64,101 +64,157 @@ bool Flip_SystemTask() 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) - { - printf("Tried to create surface with invalid id %d\n", surf_no); - return false; - } - if (surf[surf_no].texture) - { - printf("Tried to create surface at id %d, but there's already a texture there\n", surf_no); - return false; - } - - //Load surface from file - SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1); - if (!surface) - { - printf("Couldn't load bitmap for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError()); - return false; - } - - //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) - { - printf("Failed to convert SDL_Surface to SDL_Texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError()); - return false; - } - - //Create real texture, and copy loaded texture here (has texture target access) - int w, h; - SDL_QueryTexture(texture, NULL, NULL, &w, &h); + bool success = false; - SDL_Texture *textureAccessible = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, w * gWindowScale, h * gWindowScale); - - if (!textureAccessible) +#ifdef FIX_BUGS + if (surf_no >= SURFACE_ID_MAX) +#else + if (surf_no > SURFACE_ID_MAX) // OOPS (should be '>=') +#endif { - printf("Failed to create real texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError()); - return false; + printf("Tried to create drawable surface at invalid slot (%d - maximum is %d)\n", surf_no, SURFACE_ID_MAX); } - - 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; + else + { + 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; + } + } + } + } + + return success; } -bool MakeSurface_File(const char *name, int surf_no) +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) + { + 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; + } + } + + 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("Tried to load bitmap at invalid slot (%d - maximum is %d\n", surf_no, SURFACE_ID_MAX); + } + else + { + 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); + } + } + } + + return success; +} + +static bool LoadBitmap_File(const char *name, int surf_no, bool create_surface) { char path[PATH_LENGTH]; SDL_RWops *fp; @@ -168,9 +224,16 @@ bool MakeSurface_File(const char *name, int surf_no) 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,23 +241,31 @@ bool MakeSurface_File(const char *name, int surf_no) 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); 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); 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,34 +273,24 @@ bool MakeSurface_Resource(const char *res, int surf_no) return false; } +bool MakeSurface_File(const char *name, int surf_no) +{ + return LoadBitmap_File(name, surf_no, true); +} + +bool MakeSurface_Resource(const char *res, int surf_no) +{ + return LoadBitmap_Resource(res, surf_no, true); +} + bool ReloadBitmap_File(const char *name, int surf_no) { - ReleaseSurface(surf_no); - return MakeSurface_File(name, surf_no); + return LoadBitmap_File(name, surf_no, false); } bool ReloadBitmap_Resource(const char *res, int surf_no) { - ReleaseSurface(surf_no); - return MakeSurface_Resource(res, surf_no); -} - -bool MakeSurface_Generic(int bxsize, int bysize, 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_Resource(res, surf_no, false); } SDL_Rect RectToSDLRect(RECT *rect) @@ -246,42 +307,27 @@ void BackupSurface(int surf_no, RECT *rect) //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 @@ void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transpare 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 @@ void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transpare 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 @@ void Surface2Surface(int x, int y, RECT *rect, int to, int from) 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 @@ void CortBox2(RECT *rect, uint32_t col, int surf_no) //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 InitTextObject(const char *font_name) 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() @@ -505,3 +515,17 @@ void EndTextObject() 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); +} diff --git a/src/Draw.h b/src/Draw.h index 9305b816..08bc07b9 100644 --- a/src/Draw.h +++ b/src/Draw.h @@ -45,6 +45,9 @@ enum Surface_Ids struct SURFACE { + bool in_use; + bool needs_updating; + SDL_Surface *surface; SDL_Texture *texture; }; diff --git a/src/Font.cpp b/src/Font.cpp index fa097b8d..4f1613c0 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -175,20 +175,12 @@ FontObject* LoadFont(const char *font_filename, unsigned int cell_width, unsigne 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 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text 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 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text } 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 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text } 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 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text 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); } } diff --git a/src/Font.h b/src/Font.h index fbd7ddc4..528bf65a 100644 --- a/src/Font.h +++ b/src/Font.h @@ -8,5 +8,5 @@ typedef struct FontObject FontObject; 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); diff --git a/src/NpcAct.h b/src/NpcAct.h index 90677526..ca40f6ea 100644 --- a/src/NpcAct.h +++ b/src/NpcAct.h @@ -21,9 +21,10 @@ void ActNpc020(NPCHAR *npc); 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 ActNpc032(NPCHAR *npc); 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 ActNpc046(NPCHAR *npc); 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 ActNpc076(NPCHAR *npc); 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,10 +76,14 @@ void ActNpc119(NPCHAR *npc); 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); void ActNpc300(NPCHAR *npc); diff --git a/src/NpcAct020.cpp b/src/NpcAct020.cpp index 046db7fd..83c7a49c 100644 --- 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 @@ void ActNpc023(NPCHAR *npc) 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 @@ void ActNpc025(NPCHAR *npc) 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) { @@ -383,6 +742,42 @@ void ActNpc037(NPCHAR *npc) 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 void ActNpc039(NPCHAR *npc) { diff --git a/src/NpcAct060.cpp b/src/NpcAct060.cpp index 04acf303..573e8b60 100644 --- 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) { @@ -258,6 +660,142 @@ void ActNpc065(NPCHAR *npc) 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 void ActNpc070(NPCHAR *npc) { diff --git a/src/NpcAct080.cpp b/src/NpcAct080.cpp index 7855b0db..429ba103 100644 --- 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) { diff --git a/src/NpcAct140.cpp b/src/NpcAct140.cpp index 232a4857..7a83e0d6 100644 --- 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) { diff --git a/src/NpcAct260.cpp b/src/NpcAct260.cpp new file mode 100644 index 00000000..1c24abcd --- /dev/null +++ b/src/NpcAct260.cpp @@ -0,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; + } +} diff --git a/src/NpcTbl.cpp b/src/NpcTbl.cpp index 61e54126..0b79d230 100644 --- a/src/NpcTbl.cpp +++ b/src/NpcTbl.cpp @@ -80,11 +80,11 @@ NPCFUNCTION gpNpcFuncTbl[361] = ActNpc021, ActNpc022, ActNpc023, - nullptr, + ActNpc024, ActNpc025, nullptr, nullptr, - nullptr, + ActNpc028, ActNpc029, ActNpc030, nullptr, @@ -94,7 +94,7 @@ NPCFUNCTION gpNpcFuncTbl[361] = nullptr, nullptr, ActNpc037, - nullptr, + ActNpc038, ActNpc039, nullptr, nullptr, @@ -116,8 +116,8 @@ NPCFUNCTION gpNpcFuncTbl[361] = nullptr, ActNpc058, ActNpc059, - nullptr, - nullptr, + ActNpc060, + ActNpc061, ActNpc062, nullptr, ActNpc064, @@ -125,7 +125,7 @@ NPCFUNCTION gpNpcFuncTbl[361] = nullptr, nullptr, nullptr, - nullptr, + ActNpc069, ActNpc070, ActNpc071, ActNpc072, @@ -136,8 +136,8 @@ NPCFUNCTION gpNpcFuncTbl[361] = ActNpc077, ActNpc078, ActNpc079, - nullptr, - nullptr, + ActNpc080, + ActNpc081, nullptr, ActNpc083, ActNpc084, @@ -201,7 +201,7 @@ NPCFUNCTION gpNpcFuncTbl[361] = nullptr, nullptr, nullptr, - nullptr, + ActNpc145, nullptr, nullptr, nullptr, @@ -334,7 +334,7 @@ NPCFUNCTION gpNpcFuncTbl[361] = nullptr, nullptr, nullptr, - nullptr, + ActNpc278, nullptr, nullptr, nullptr, diff --git a/src/Sound.cpp b/src/Sound.cpp index e5763a9b..39c0734e 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -129,7 +129,7 @@ float MillibelToVolume(int32_t lVolume) { //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,36 +174,32 @@ void SOUNDBUFFER::Stop() SDL_UnlockAudioDevice(audioDevice); } -void SOUNDBUFFER::Mix(float *buffer, int len) +void SOUNDBUFFER::Mix(float (*buffer)[2], size_t samples) { if (this == NULL) return; 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 @@ void SOUNDBUFFER::Mix(float *buffer, int len) //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 diff --git a/src/Sound.h b/src/Sound.h index 3c02e75f..2e78292c 100644 --- a/src/Sound.h +++ b/src/Sound.h @@ -20,7 +20,7 @@ class SOUNDBUFFER void Play(bool bLooping); void Stop(); - void Mix(float *buffer, int len); + void Mix(float (*buffer)[2], size_t samples); SOUNDBUFFER *next;