325 lines
14 KiB
C
325 lines
14 KiB
C
//
|
||
// Created by bruno on 4/24/25.
|
||
//
|
||
|
||
#include <SDL2/SDL_rect.h>
|
||
#include "player.h"
|
||
#include "../tiles/tile.h"
|
||
#include "../util/font.h"
|
||
#include "../util/atlas.h"
|
||
#include "../entity/entity.h"
|
||
|
||
#define HEALTH_MARGIN 4
|
||
|
||
Player mainPlayer;
|
||
|
||
int playerSpeed = 2;
|
||
|
||
int playerReach = 5;
|
||
|
||
SDL_Texture *entityTexture;
|
||
SDL_Texture *hudTexture;
|
||
|
||
SDL_Texture *PlayerTexture;
|
||
SDL_Rect PlayerRect;
|
||
SDL_Rect playerTextureRect;
|
||
|
||
SDL_Rect targetItemBGRect;
|
||
SDL_Rect waveInfoBGRect;
|
||
|
||
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 = 10 * TILE_SIZE;
|
||
plr->rect.y = (MAP_HEIGHT - 10) * TILE_SIZE;
|
||
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.x = 0;
|
||
targetItemBGRect.h = (TILE_SIZE / 2) + fonts[2].size * 2;
|
||
targetItemBGRect.y = DISPLAY_HEIGHT - (TILE_SIZE / 2) - fonts[2].size * 2;
|
||
|
||
waveInfoBGRect.y = 0;
|
||
waveInfoBGRect.x = 0;
|
||
waveInfoBGRect.w = 450;
|
||
waveInfoBGRect.h = 80;
|
||
|
||
targetItemRect.w = TILE_SIZE / 2;
|
||
targetItemRect.h = TILE_SIZE / 2;
|
||
|
||
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 = 10 * TILE_SIZE;
|
||
plr->rect.y = (MAP_HEIGHT - 10) * TILE_SIZE;
|
||
}
|
||
}
|
||
|
||
|
||
void renderPlayer(Player *plr) {
|
||
|
||
SDL_Texture *originalTarget = SDL_GetRenderTarget(mainRenderer);
|
||
|
||
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 0);
|
||
|
||
SDL_SetRenderTarget(mainRenderer, entityTexture);
|
||
double angle = angle_between_points_deg(PlayerRect.x, PlayerRect.y, plr->cursor.windowX, plr->cursor.windowY) + 90;
|
||
SDL_RenderCopyEx(mainRenderer, atlasTexture, &playerTextureRect, &PlayerRect, angle, NULL, SDL_FLIP_NONE);
|
||
//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);
|
||
targetItemBGRect.h = (TILE_SIZE / 2) + fonts[2].size * 2;
|
||
targetItemBGRect.w = DISPLAY_WIDTH;
|
||
targetItemBGRect.y = DISPLAY_HEIGHT - (TILE_SIZE / 2) - fonts[2].size * 2;
|
||
SDL_RenderFillRect(mainRenderer, &targetItemBGRect);
|
||
SDL_RenderFillRect(mainRenderer, &waveInfoBGRect);
|
||
|
||
|
||
char hudStr[80];
|
||
char waveStr[50];
|
||
if (entities.activeCount > 0) {
|
||
snprintf(waveStr, 50, "Remaining enemies: %d", entities.activeCount);
|
||
} else {
|
||
snprintf(waveStr, 50, "Next wave in: %dm %ds", waveInfo.waveTimer / 3600, (waveInfo.waveTimer / 60) % 60);
|
||
}
|
||
snprintf(hudStr, 80, "Wave: %d/%d\n%s\n", waveInfo.waveCounter, waveInfo.totalWaves, waveStr);
|
||
renderText(mainRenderer, fonts[1], hudStr, 0, 0);
|
||
|
||
targetItemRect.y = DISPLAY_HEIGHT - (TILE_SIZE / 2);
|
||
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;
|
||
}
|
||
}
|
||
SDL_SetTextureBlendMode(atlasTexture, SDL_BLENDMODE_BLEND);
|
||
|
||
SDL_SetRenderTarget(mainRenderer, originalTarget);
|
||
} |