Files
factorygame/player/player.c

325 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// 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++;
// Dont 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);
}