// // Created by bruno on 4/24/25. // #include #include "util.h" #include "../tiles/tile.h" #include "font.h" //#include "font.h" //The window we'll be rendering to SDL_Window *window = NULL; volatile bool running = true; WaveInfo waveInfo; const char OrientStrings[ORIENT_DIRECTION_COUNT][10] = { "LEFT_DOWN", "LEFT", "LEFT_UP", "UP", "RIGHT_UP", "RIGHT", "RIGHT_DOWN", "DOWN", }; int animationStep = 0; bool debugMode = false; bool itemViewing = false; bool renderAtlas = false; //The surface contained by the window SDL_Renderer *mainRenderer = NULL; SDL_Rect screenRect; SDL_Texture *createFlippedTexture(SDL_Renderer *renderer, SDL_Texture *src, SDL_RendererFlip flip) { int w, h; SDL_QueryTexture(src, NULL, NULL, &w, &h); SDL_Texture *renderTarget = SDL_GetRenderTarget(renderer); SDL_Texture *target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h); SDL_SetRenderTarget(renderer, target); SDL_RenderCopyEx(renderer, src, NULL, NULL, 0, NULL, flip); SDL_SetRenderTarget(renderer, renderTarget); return target; } SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle) { int w, h; SDL_QueryTexture(src, NULL, NULL, &w, &h); SDL_Texture *renderTarget = SDL_GetRenderTarget(renderer); SDL_Texture *target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h); SDL_SetRenderTarget(renderer, target); SDL_RenderCopyEx(renderer, src, NULL, NULL, angle, NULL, SDL_FLIP_NONE); SDL_SetRenderTarget(renderer, renderTarget); return target; } SDL_Texture *ScaleTexture(SDL_Renderer *renderer, SDL_Texture *src, int newWidth, int newHeight) { SDL_Texture *scaledTex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, newWidth, newHeight); if (!scaledTex) { SDL_Log("Failed to create target texture: %s", SDL_GetError()); return nullptr; } // Save current render target SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer); SDL_SetRenderTarget(renderer, scaledTex); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); SDL_Rect dst = {0, 0, newWidth, newHeight}; SDL_RenderCopy(renderer, src, NULL, &dst); SDL_SetRenderTarget(renderer, oldTarget); // Restore return scaledTex; } void DrawThickRect(SDL_Renderer *renderer, SDL_Rect rect, int thickness) { for (int i = 0; i < thickness; i++) { SDL_Rect r = {rect.x - i, rect.y - i, rect.w + i * 2, rect.h + i * 2}; SDL_RenderDrawRect(renderer, &r); } } void renderBar(SDL_Renderer *renderer, int x, int y, int width, int height, int maxValue, int currentValue, SDL_Color barColor, int margin) { if (maxValue <= 0) return; // Avoid division by zero // Clamp value if (currentValue < 0) currentValue = 0; if (currentValue == 0) { return; } if (currentValue > maxValue) currentValue = maxValue; // Calculate filled width based on currentValue int filledWidth = (width * currentValue) / maxValue; // Bar rectangle SDL_Rect barRect = {x, y, filledWidth, height}; // Background rectangle with margin SDL_Rect bgRect = { x - margin, y - margin, width + margin * 2, height + margin * 2 }; // Draw background (black) SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderFillRect(renderer, &bgRect); // Draw bar with provided color SDL_SetRenderDrawColor(renderer, barColor.r, barColor.g, barColor.b, barColor.a); SDL_RenderFillRect(renderer, &barRect); char barString[20]; sprintf(barString, "%d/%d", currentValue, maxValue); renderText(mainRenderer, fonts[1], barString, x + (width / 2 - (fonts[2].size * strlen(barString))), y - fonts[2].size - barRect.h); } int cmpstringp(const void *p1, const void *p2) { return strcmp(*(const char **) p1, *(const char **) p2); } // Helper function to iterate over sorted entries in a directory void iterateSortedDir(const char *path, DirEntryCallback callback, SDL_Renderer *renderer) { DIR *dir = opendir(path); if (!dir) { perror("opendir"); return; } struct dirent *entry; char **names = NULL; size_t count = 0; // Collect file names while ((entry = readdir(dir)) != NULL) { if (entry->d_name[0] == '.') continue; names = realloc(names, sizeof(char *) * (count + 1)); if (!names) { perror("realloc"); closedir(dir); return; } names[count++] = strdup(entry->d_name); } closedir(dir); // Sort entries qsort(names, count, sizeof(char *), cmpstringp); // Call the user-provided function for each file if (names != NULL) { for (size_t i = 0; i < count; i++) { if (names[i] != NULL) { callback(names[i], renderer); free(names[i]); } } free(names); } } bool checkCollision(SDL_Rect a, SDL_Rect b) { //The sides of the rectangles int leftA, leftB; int rightA, rightB; int topA, topB; int bottomA, bottomB; //Calculate the sides of tileRect A leftA = a.x; rightA = a.x + a.w; topA = a.y; bottomA = a.y + a.h; //Calculate the sides of tileRect B leftB = b.x; rightB = b.x + b.w; topB = b.y; bottomB = b.y + b.h; //If any of the sides from A are outside of B if (bottomA <= topB) { return false; } if (topA >= bottomB) { return false; } if (rightA <= leftB) { return false; } if (leftA >= rightB) { return false; } //If none of the sides from A are outside B return true; } bool canMoveTo(SDL_Rect newRect) { // Round down to get all tiles the rect overlaps int left = newRect.x / TILE_SIZE; int right = (newRect.x + newRect.w - 1) / TILE_SIZE; int top = newRect.y / TILE_SIZE; int bottom = (newRect.y + newRect.h - 1) / TILE_SIZE; for (int tx = left; tx <= right; ++tx) { for (int ty = top; ty <= bottom; ++ty) { MiniRect tile = { tx, ty }; if (!isWalkable(tile)) { return false; } } } return true; } bool canMoveWithRadius(SDL_Rect centerRect) { // 16px radius — create a square bounding box around center int radius = 16; int left = (centerRect.x - radius) / TILE_SIZE; int right = (centerRect.x + radius - 1) / TILE_SIZE; int top = (centerRect.y - radius) / TILE_SIZE; int bottom = (centerRect.y + radius - 1) / TILE_SIZE; int x, y; for (x = left; x <= right; x++) { for (y = top; y <= bottom; y++) { MiniRect tile; tile.x = x; tile.y = y; if (!isWalkable(tile)) { // Get pixel bounds of tile int tileLeft = x * TILE_SIZE; int tileRight = tileLeft + TILE_SIZE; int tileTop = y * TILE_SIZE; int tileBottom = tileTop + TILE_SIZE; // Bounding box of the player int playerLeft = centerRect.x - radius; int playerRight = centerRect.x + radius; int playerTop = centerRect.y - radius; int playerBottom = centerRect.y + radius; // AABB collision check if (playerRight > tileLeft && playerLeft < tileRight && playerBottom > tileTop && playerTop < tileBottom) { return 0; // Collision } } } } return 1; // No collisions } int compareStrings(const void *a, const void *b) { const char *strA = *(const char **) a; const char *strB = *(const char **) b; return strcmp(strA, strB); }