// // Created by bruno on 4/24/25. // #include #include "player.h" #include "../tiles/tile.h" #define HEALTH_MARGIN 4 int playerSpeed = 4; int playerReach = 4; SDL_Texture *PlayerTexture; SDL_Rect PlayerRect; void setActivePlayerSlot(Player *plr, uint16_t activeSlotIndex) { activeSlotIndex = activeSlotIndex % itemRegistryIndex; if (activeSlotIndex <= 0) { activeSlotIndex = 1; } plr->inventory.activeSlotIndex = activeSlotIndex; } void moveActivePlayerSlot(Player *plr, bool up, bool seek) { if (seek) { uint16_t prevSlot = plr->inventory.activeSlotIndex; uint16_t newSlot = prevSlot; do { newSlot = (newSlot + (up ? 1 : ITEMREGISTRY_SIZE - 1)) % ITEMREGISTRY_SIZE; // Stop if we've looped all the way around if (newSlot == prevSlot) break; // Stop if we found a slot with count > 0 if (plr->inventory.slotCounts[newSlot] > 0) break; } while (true); plr->inventory.activeSlotIndex = newSlot; } else { if (plr->inventory.activeSlotIndex == 1 && !up) { plr->inventory.activeSlotIndex = itemRegistryIndex - 1; } else if (plr->inventory.activeSlotIndex == itemRegistryIndex - 1 && up) { plr->inventory.activeSlotIndex = 1; } else { plr->inventory.activeSlotIndex = (plr->inventory.activeSlotIndex + (up ? 1 : ITEMREGISTRY_SIZE - 1)) % ITEMREGISTRY_SIZE; } } } int playerX = (MAP_WIDTH / 2) * 16; int playerY = (MAP_HEIGHT / 2) * 16; void adjustRect(SDL_Rect *rect) { rect->x -= playerX; rect->y -= playerY; rect->x += DISPLAY_WIDTH / 2; rect->y += DISPLAY_HEIGHT / 2; } bool isInboundsTile(int x, int y) { return (playerX / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2) < x && (playerY / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2) < y && (playerX / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) > x && (playerX / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) > y; } bool isInbounds(int x, int y) { return x > 0 && y > 0 && x < DISPLAY_WIDTH && y < DISPLAY_HEIGHT; } bool isInboundsRect(SDL_Rect rect) { if (isInbounds(rect.x, rect.y)) { return true; } if (rect.x < 0) { rect.x += rect.w; } if (rect.y < 0) { rect.y += rect.h; } if (isInbounds(rect.x, rect.y)) { return true; } if (rect.x > DISPLAY_WIDTH) { rect.x -= rect.w; } if (rect.y > DISPLAY_HEIGHT) { rect.y -= rect.h; } return isInbounds(rect.x, rect.y); } void initPlayer(Player *plr) { plr->cursor.direction = ORIENT_UP; setActivePlayerSlot(plr, 1); PlayerTexture = IMG_LoadTexture(renderer, "assets/player.png"); SDL_QueryTexture(PlayerTexture, NULL, NULL, &PlayerRect.w, &PlayerRect.h); PlayerRect.x = (DISPLAY_WIDTH / 2) - (PlayerRect.w / 2); PlayerRect.y = (DISPLAY_HEIGHT / 2) - (PlayerRect.h / 2); plr->health = 64; plr->healthIdle = 0; } void updatePlayer(Player *plr) { if (plr->health == plr->prevHealth && plr->healthIdle < neededHealthIdle) { plr->healthIdle++; } if (plr->health < playerMaxHealth && plr->healthIdle >= neededHealthIdle) { plr->health++; } plr->prevHealth = plr->health; } void renderPlayer(Player *plr) { plr->cursor.targetTileRect.x = plr->cursor.tileX * TILE_SIZE; plr->cursor.targetTileRect.y = plr->cursor.tileY * TILE_SIZE; plr->cursor.targetTileRect.w = TILE_SIZE; plr->cursor.targetTileRect.h = TILE_SIZE; SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); plr->cursor.tileDiffX = plr->cursor.tileX - playerTileX; plr->cursor.tileDiffY = plr->cursor.tileY - playerTileY; if (abs(plr->cursor.tileDiffX) > abs(plr->cursor.tileDiffY)) { plr->cursor.tileDiff = plr->cursor.tileDiffX; } else { plr->cursor.tileDiff = plr->cursor.tileDiffY; } plr->cursor.canReach = abs(plr->cursor.tileDiff) <= playerReach; SDL_SetRenderDrawColor(renderer, plr->cursor.canReach ? 0 : 255, plr->cursor.canReach ? 255 : 0, 0, 128); adjustRect(&plr->cursor.targetTileRect); DrawThickRect(renderer, plr->cursor.targetTileRect, 4); uint16_t itemIndex = plr->inventory.activeSlotIndex; if (itemIndex < itemRegistryIndex) { SDL_Rect heldItemRect; heldItemRect.x = plr->cursor.windowX; heldItemRect.y = plr->cursor.windowY; heldItemRect.w = TILE_SIZE; heldItemRect.h = TILE_SIZE; SDL_Texture *itemTex = ItemRegistry[itemIndex].textureOnBelt[plr->cursor.direction]; if (itemTex == NULL) { itemTex = ItemRegistry[itemIndex].textureOnBelt[ORIENT_LEFT]; } if (itemTex != NULL) { if (plr->inventory.slotCounts[itemIndex] <= 0) { // Set a red tint (255, 0, 0) SDL_SetTextureColorMod(itemTex, 128, 128, 255); SDL_SetTextureAlphaMod(itemTex, 192); } else { SDL_SetTextureColorMod(itemTex, 255, 255, 255); SDL_SetTextureAlphaMod(itemTex, 255); } SDL_RenderCopy(renderer, itemTex, NULL, &heldItemRect); } } SDL_RenderCopy(renderer, PlayerTexture, NULL, &PlayerRect); SDL_Color healthBarColor = {0, 240, 0, 255}; renderBar(renderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 50, 200, 8, playerMaxHealth, plr->health, healthBarColor, 4); SDL_Color breakingBarColor = {128, 128, 0, 255}; renderBar(renderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 70, 200, 8, getBreakTime(plr->cursor.targetTile->type), plr->cursor.breakingProgress, breakingBarColor, 4); SDL_Rect targetItemBGRect; targetItemBGRect.w = DISPLAY_WIDTH; targetItemBGRect.h = TILE_SIZE; targetItemBGRect.x = 0; targetItemBGRect.y = DISPLAY_HEIGHT - 30; SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderFillRect(renderer, &targetItemBGRect); SDL_Rect targetItemRect; targetItemRect.w = TILE_SIZE / 2; targetItemRect.h = TILE_SIZE / 2; targetItemRect.y = DISPLAY_HEIGHT - 30 + TILE_SIZE / 4; targetItemRect.x = TILE_SIZE / 4; for (uint16_t i = 1; i < ITEMREGISTRY_SIZE; i++) { SDL_Texture *itemTex = ItemRegistry[i].textureOnBelt[plr->cursor.direction]; if (itemTex == NULL) { itemTex = ItemRegistry[i].textureOnBelt[ORIENT_LEFT]; } if (itemTex != NULL) { if (plr->inventory.slotCounts[i] <= 0) { // Set a red tint (255, 0, 0) SDL_SetTextureColorMod(itemTex, 128, 128, 255); } SDL_RenderCopy(renderer, itemTex, NULL, &targetItemRect); SDL_SetTextureColorMod(itemTex, 255, 255, 255); } if (plr->inventory.activeSlotIndex == i) { SDL_SetRenderDrawColor(renderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16, plr->inventory.slotCounts[i] > 0 ? 32 : 128, 255); DrawThickRect(renderer, targetItemRect, 4); } targetItemRect.x += (TILE_SIZE / 2) + (TILE_SIZE / 4); } }