// // Created by bruno on 4/24/25. // #include #include "player.h" #include "../tiles/tile.h" #include "../util/font.h" #include "../util/atlas.h" #define HEALTH_MARGIN 4 int playerSpeed = 2; int playerReach = DISPLAY_MAP_HEIGHT / 2 - 2; SDL_Texture *entityTexture; SDL_Texture *hudTexture; SDL_Texture *PlayerTexture; SDL_Rect PlayerRect; SDL_Rect playerTextureRect; SDL_Rect targetItemBGRect; SDL_Rect targetItemRect; SDL_Color healthBarColor = {0, 240, 0, 255}; SDL_Color breakingBarColor = {128, 128, 0, 255}; void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) { activeSlotIndex = activeSlotIndex % itemRegistryIndex; if ((activeSlotIndex < tileTypeIndex || (activeSlotIndex < itemRegistryIndex && activeSlotIndex >= ITEMREGISTRY_SIZE / 2)) && activeSlotIndex > 0) { plr->inventory.activeSlotIndex = activeSlotIndex; } } void moveActivePlayerSlot(Player *plr, bool up, bool seek) { ItemType prevSlot = plr->inventory.activeSlotIndex; ItemType 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 (!strlen(ItemRegistry[newSlot].name)) continue; if (newSlot == 0) break; if (seek) { if (plr->inventory.slotCounts[newSlot] > 0) break; } else { break; } } while (true); plr->inventory.activeSlotIndex = newSlot; } inline void adjustRect(SDL_Rect *rect, SDL_Rect playerRect) { rect->x -= playerRect.x; rect->y -= playerRect.y; 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 tileRect) { // if (isInbounds(tileRect.x, tileRect.y)) { // return true; // } // if (tileRect.x < 0) { // tileRect.x += tileRect.w; // } // if (tileRect.y < 0) { // tileRect.y += tileRect.h; // } // if (isInbounds(tileRect.x, tileRect.y)) { // return true; // } // if (tileRect.x > DISPLAY_WIDTH) { // tileRect.x -= tileRect.w; // } // if (tileRect.y > DISPLAY_HEIGHT) { // tileRect.y -= tileRect.h; // } // return isInbounds(tileRect.x, tileRect.y); //} void initPlayer(Player *plr) { plr->cursor.direction = ORIENT_UP; setActivePlayerSlot(plr, 1); PlayerTexture = IMG_LoadTexture(mainRenderer, "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); playerTextureRect = allocate_32x32(PlayerTexture, mainRenderer); plr->health = 64; plr->healthIdle = 0; plr->rect.x = DISPLAY_WIDTH / 2; plr->rect.y = DISPLAY_HEIGHT / 2; plr->rect.w = TILE_SIZE; plr->rect.h = TILE_SIZE; for (ItemType ui = 1; ui < tileTypeIndex; ui++) { plr->inventory.slotCounts[ui] = 32; } for (ItemType ui = ITEMREGISTRY_SIZE / 2; ui < itemRegistryIndex; ui++) { plr->inventory.slotCounts[ui] = 0; } hudTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w, screenRect.h); entityTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w, screenRect.h); SDL_SetTextureBlendMode(entityTexture, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(hudTexture, SDL_BLENDMODE_BLEND); plr->cursor.targetTileRect.w = TILE_SIZE; plr->cursor.targetTileRect.h = TILE_SIZE; plr->cursor.targetTileRect.w = TILE_SIZE; plr->cursor.targetTileRect.h = TILE_SIZE; targetItemBGRect.w = DISPLAY_WIDTH; targetItemBGRect.h = TILE_SIZE + fonts[2].size * 2; targetItemBGRect.x = 0; targetItemBGRect.y = DISPLAY_HEIGHT - TILE_SIZE - fonts[2].size * 2; targetItemRect.w = TILE_SIZE; targetItemRect.h = TILE_SIZE; plr->cursor.heldItemRect.w = TILE_SIZE; plr->cursor.heldItemRect.h = TILE_SIZE; } void updatePlayer(Player *plr) { if (plr->health == plr->prevHealth) { if (plr->healthIdle < neededHealthIdle) plr->healthIdle++; } else { plr->healthIdle = 0; // Reset if health changed (e.g., took damage or regen happened) } if (plr->health < playerMaxHealth && plr->healthIdle >= neededHealthIdle) { plr->health++; // Don’t reset healthIdle here — only reset if something changes externally } plr->prevHealth = plr->health; if (plr->health <= 0) { plr->rect.x = DISPLAY_WIDTH / 2; plr->rect.y = DISPLAY_HEIGHT / 2; } } void renderPlayer(Player *plr) { SDL_Texture *originalTarget = SDL_GetRenderTarget(mainRenderer); SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 0); SDL_SetRenderTarget(mainRenderer, entityTexture); SDL_RenderCopy(mainRenderer, atlasTexture, &playerTextureRect, &PlayerRect); //SDL_RenderCopy(mainRenderer, PlayerTexture, NULL, &PlayerRect); SDL_SetRenderTarget(mainRenderer, hudTexture); SDL_RenderClear(mainRenderer); SDL_SetRenderDrawColor(mainRenderer, plr->cursor.canReach ? 0 : 255, plr->cursor.canReach ? 255 : 0, 0, 128); DrawThickRect(mainRenderer, plr->cursor.targetTileRect, 4); ItemType itemIndex = plr->inventory.activeSlotIndex; //SDL_Texture *itemTex; char itemStringCount[6]; if ((itemIndex < tileTypeIndex || (itemIndex < itemRegistryIndex && itemIndex >= ITEMREGISTRY_SIZE / 2)) && itemIndex > 0) { plr->cursor.heldItemRect.x = plr->cursor.windowX; plr->cursor.heldItemRect.y = plr->cursor.windowY; //itemTex = ItemRegistry[itemIndex].textureOnBelt[plr->cursor.direction]; SDL_Rect itemAtlasRect = ItemRegistry[itemIndex].animation.atlasRects[plr->cursor.direction][( (animationStep / ItemRegistry[itemIndex].beltAnimation.divisor) % ( ItemRegistry[itemIndex].beltAnimation.frameCount - ItemRegistry[itemIndex].beltAnimation.startFrame)) + ItemRegistry[itemIndex].beltAnimation.startFrame]; if (itemAtlasRect.w == 0 || itemAtlasRect.h == 0) { itemAtlasRect = ItemRegistry[itemIndex].animation.atlasRects[ORIENT_LEFT][( (animationStep / ItemRegistry[itemIndex].beltAnimation.divisor) % ( ItemRegistry[itemIndex].beltAnimation.frameCount - ItemRegistry[itemIndex].beltAnimation.startFrame)) + ItemRegistry[itemIndex].beltAnimation.startFrame]; } if (itemAtlasRect.w != 0 && itemAtlasRect.h != 0) { if (plr->inventory.slotCounts[itemIndex] <= 0) { // Set a red tint (255, 0, 0) SDL_SetTextureColorMod(atlasTexture, 128, 128, 255); SDL_SetTextureAlphaMod(atlasTexture, 230); } else { SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); SDL_SetTextureAlphaMod(atlasTexture, 255); } // SDL_RenderCopy(mainRenderer, itemTex, NULL, // &plr->cursor.heldItemRect); char nameItem[80]; snprintf(nameItem, 80, "%s\n%s", ItemRegistry[itemIndex].name, OrientStrings[plr->cursor.direction]); SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRect, &plr->cursor.heldItemRect); renderText(mainRenderer, fonts[2], nameItem, plr->cursor.heldItemRect.x, plr->cursor.heldItemRect.y - (fonts[2].size * 3 / 2)); } SDL_SetTextureAlphaMod(atlasTexture, 255); SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); } renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 70, 200, 8, playerMaxHealth, plr->health, healthBarColor, 4); if (plr->cursor.targetTile) { uint16_t tempko = getBreakTime(plr->cursor.targetTile->type); uint16_t tempko2 = plr->cursor.breakingProgress; renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 110, 200, 8, tempko, tempko2, breakingBarColor, 4); } SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255); SDL_RenderFillRect(mainRenderer, &targetItemBGRect); targetItemRect.y = DISPLAY_HEIGHT - TILE_SIZE; targetItemRect.x = TILE_SIZE / 4; SDL_SetTextureBlendMode(atlasTexture, SDL_BLENDMODE_ADD); for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) { if (ItemRegistry[i].name[0] == 0x00) { continue; } SDL_Rect itemAtlasRectd = ItemRegistry[i].animation.atlasRects[plr->cursor.direction][( (animationStep / ItemRegistry[i].beltAnimation.divisor) % ( ItemRegistry[i].beltAnimation.frameCount - ItemRegistry[i].beltAnimation.startFrame)) + ItemRegistry[i].beltAnimation.startFrame]; if (itemAtlasRectd.w == 0 || itemAtlasRectd.h == 0) { itemAtlasRectd = ItemRegistry[i].animation.atlasRects[ORIENT_LEFT][( (animationStep / ItemRegistry[i].beltAnimation.divisor) % ( ItemRegistry[i].beltAnimation.frameCount - ItemRegistry[i].beltAnimation.startFrame)) + ItemRegistry[i].beltAnimation.startFrame]; } if (itemAtlasRectd.w != 0 && itemAtlasRectd.h != 0) { if (plr->inventory.slotCounts[i] <= 0) { // Set a red tint (255, 0, 0) SDL_SetTextureColorMod(atlasTexture, 128, 128, 255); } SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRectd, &targetItemRect); SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); if (plr->inventory.activeSlotIndex == i) { SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16, plr->inventory.slotCounts[i] > 0 ? 32 : 128, 255); DrawThickRect(mainRenderer, targetItemRect, 4); } sprintf(itemStringCount, "%d", plr->inventory.slotCounts[i]); renderText(mainRenderer, fonts[2], itemStringCount, targetItemRect.x - 3, targetItemRect.y - (fonts[2].size * 3 / 2)); //targetItemRect.x += (TILE_SIZE / 2) + (TILE_SIZE / 4); targetItemRect.x += TILE_SIZE / 2 * 3; } } SDL_SetTextureBlendMode(atlasTexture, SDL_BLENDMODE_BLEND); SDL_SetRenderTarget(mainRenderer, originalTarget); }