Files
factorygame/items/item.c
2025-05-30 22:31:59 +02:00

312 lines
11 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 "item.h"
#include "../player/player.h"
#include "../util/font.h"
#include <dirent.h>
Item ItemRegistry[ITEMREGISTRY_SIZE];
uint16_t itemRegistryIndex = 0;
float speed = 0.002f; // fraction of tile per tick
void updateItems() {
const int dirDx[8] = {-1, -1, -1, 0, 1, 1, 1, 0};
const int dirDy[8] = {1, 0, -1, -1, -1, 0, 1, 1};
const float epsilon = 0.999f; // if we can't move, back it off just below 1
for (int y = 0; y < MAP_HEIGHT; y++) {
for (int x = 0; x < MAP_WIDTH; x++) {
Tile *t = &tileMap[y][x];
if (t->type != TYPE_BELT) continue;
int dir = t->direction;
bool horz = (dir == ORIENT_LEFT || dir == ORIENT_RIGHT);
bool vert = (dir == ORIENT_UP || dir == ORIENT_DOWN);
for (uint8_t lane = 0; lane < 2; lane++) {
for (uint8_t slot = 0; slot < 2; slot++) {
ItemOnBelt *itm = &t->items[lane][slot];
if (!itm->active) continue;
// 1) Advance
itm->offset += speed;
// 2) Time to hop?
if (itm->offset >= 0.5f) {
itm->offset -= 1.0f;
// target coords
int nx = x + dirDx[dir];
int ny = y + dirDy[dir];
// bounds & belt?
if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) {
itm->active = false;
continue;
}
Tile *next = &tileMap[ny][nx];
if (next->type != TYPE_BELT) {
itm->active = false;
continue;
}
// Decide new lane
int newLane = lane;
int newDir = next->direction;
bool nH = (newDir == ORIENT_LEFT || newDir == ORIENT_RIGHT);
bool nV = (newDir == ORIENT_UP || newDir == ORIENT_DOWN);
if ((horz && nH) || (vert && nV)) {
// same axis → keep lane
} else if (horz && nV) {
// came off a horizontal: lane0=top→vertical.left, lane1=bottom→vertical.right
newLane = (dir == ORIENT_RIGHT ? 1 : 0);
itm->offset = 0.0f;
} else if (vert && nH) {
// came off vertical: lane0=left→horizontal.top, lane1=right→horizontal.bottom
newLane = (dir == ORIENT_UP ? 0 : 1);
itm->offset = 0.0f;
}
// (diagonals fall back to same-lane)
// Find a free slot in newLane
int destSlot = -1;
if (!next->items[newLane][0].active) destSlot = 0;
else if (!next->items[newLane][1].active) destSlot = 1;
if (destSlot >= 0) {
// MOVE it
ItemOnBelt moved = *itm;
moved.tileX = nx;
moved.tileY = ny;
next->items[newLane][destSlot] = moved;
next->items[newLane][destSlot].active = true;
// clear this one
itm->active = false;
} else {
// both slots full → wait at end
itm->offset = epsilon;
}
}
}
}
}
}
}
void registerItem(char name[20], SDL_Renderer *renderer) {
const char *dot = strchr(name, '.');
memcpy(ItemRegistry[itemRegistryIndex].name, name, dot - name);
char texturePath[80];
snprintf(texturePath, 80, "./assets/items/%s", name);
ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT] = IMG_LoadTexture(renderer, texturePath);
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].texture[0], SDL_BLENDMODE_BLEND);
ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT] = ScaleTexture(renderer, ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT],
TILE_SIZE / 2, TILE_SIZE / 2);
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
itemRegistryIndex++;
}
// easing function: cosine easeinout
static float ease_in_out(float t) {
if (t < -1.0f) t = -1.0f;
if (t > 1.0f) t = 1.0f;
// Even symmetric easing: reflected across t = 0
return (t < 0.0f)
? -0.5f * (1.0f - cosf(M_PI * -t)) // negative side
: 0.5f * (1.0f - cosf(M_PI * t)); // positive side
}
uint8_t laneTarget = 0;
void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane) {
SDL_Rect rect = {0};
rect.x = item.tileX * TILE_SIZE;
rect.y = item.tileY * TILE_SIZE;
// get raw direction code
int dir = tileMap[item.tileY][item.tileX].direction;
//--- 1) build a unit vector (dxf, dyf) for this orientation
float dxf = 0.0f, dyf = 0.0f;
const float D = M_SQRT1_2; // 1/√2 ≈ 0.7071
switch (dir) {
case ORIENT_LEFT_DOWN:
dxf = -D;
dyf = +D;
break;
case ORIENT_LEFT:
dxf = -1.0f;
dyf = 0.0f;
break;
case ORIENT_LEFT_UP:
dxf = -D;
dyf = -D;
break;
case ORIENT_UP:
dxf = 0.0f;
dyf = -1.0f;
break;
case ORIENT_RIGHT_UP:
dxf = +D;
dyf = -D;
break;
case ORIENT_RIGHT:
dxf = +1.0f;
dyf = 0.0f;
break;
case ORIENT_RIGHT_DOWN:
dxf = +D;
dyf = +D;
break;
case ORIENT_DOWN:
dxf = 0.0f;
dyf = +1.0f;
break;
default:
break;
}
//--- 2) ease the offset and compute forward distance
float t = ease_in_out(item.offset); // 0..1
float dist = t * TILE_SIZE; // 0..TILE_SIZE pixels
float xOffset = dxf * dist;
float yOffset = dyf * dist;
switch (dir) {
case ORIENT_LEFT_DOWN:
xOffset += 0.0f * TILE_SIZE;
yOffset += 0.0f * TILE_SIZE;
break;
case ORIENT_LEFT:
xOffset += 0.0f * TILE_SIZE;
yOffset += 0.26f * TILE_SIZE;
break;
case ORIENT_LEFT_UP:
xOffset += 0.0f * TILE_SIZE;
yOffset += 0.0f * TILE_SIZE;
break;
case ORIENT_UP:
xOffset += 0.22f * TILE_SIZE; //GOTO HEHREHRHE
yOffset += 0.0f * TILE_SIZE;
break;
case ORIENT_RIGHT_UP:
xOffset += 0.0f * TILE_SIZE;
yOffset += 0.0f * TILE_SIZE;
break;
case ORIENT_RIGHT:
xOffset += 0.0f * TILE_SIZE;
yOffset += 0.18f * TILE_SIZE; //FIX THIS
break;
case ORIENT_RIGHT_DOWN:
xOffset += 0.0f * TILE_SIZE;
yOffset += 0.0f * TILE_SIZE;
break;
case ORIENT_DOWN:
xOffset += 0.18f * TILE_SIZE;
yOffset += 0.0f * TILE_SIZE;
break;
default:
break;
}
//--- 3) compute perpendicular unit vector (perpX, perpY) = (-dy, dx)
float perpX = -dyf;
float perpY = dxf;
// perp is already unit length because (dxf,dyf) is unit
bool horz = (dir == ORIENT_LEFT || dir == ORIENT_RIGHT);
bool vert = (dir == ORIENT_UP || dir == ORIENT_DOWN);
//--- 4) lane offset
// total lane spacing = TILE_SIZE/2, so half of that each side = TILE_SIZE/4
float laneSign = (lane == laneTarget ? +1.0f : -1.0f);
float laneOffset = TILE_SIZE * (horz ? 0.12f : 0.14f); // = TILE_SIZE/4
xOffset += perpX * laneSign * laneOffset;
yOffset += perpY * laneSign * laneOffset;
//--- 5) apply to rect
rect.x += (int) roundf(xOffset);
rect.y += (int) roundf(yOffset);
rect.w = TILE_SIZE / 2;
rect.h = TILE_SIZE / 2;
adjustRect(&rect);
// (Optional debug overlay)
// SDL_Rect tileArea = {item.tileX * TILE_SIZE, item.tileY * TILE_SIZE,
// TILE_SIZE, TILE_SIZE};
// SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 32);
// adjustRect(&tileArea);
// SDL_RenderFillRect(renderer, &tileArea);
char tempStr[50];
// SDL_Rect rectA = {0};
// rectA.x = item.tileX * TILE_SIZE;
// rectA.y = item.tileY * TILE_SIZE;
// rectA.w = TILE_SIZE;
// rectA.h = TILE_SIZE;
// sprintf(tempStr, "L%d\n%f\n%f\n%f", lane, item.offset, xOffset, yOffset);
// SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 32);
// adjustRect(&rectA);
// SDL_RenderFillRect(renderer, &rectA);
SDL_RenderCopy(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &rect);
// renderText(renderer, fonts[3], tempStr, rectA.x, rectA.y);
}
void renderBeltItems(SDL_Renderer *renderer) {
}
void putItem(int x, int y, uint16_t itemType, uint8_t lane, uint8_t itemIndex) {
tileMap[y][x].items[lane][itemIndex].type = itemType;
tileMap[y][x].items[lane][itemIndex].offset = 0;
tileMap[y][x].items[lane][itemIndex].active = true;
tileMap[y][x].items[lane][itemIndex].tileX = x;
tileMap[y][x].items[lane][itemIndex].tileY = y;
}
void loadItems(SDL_Renderer *renderer) {
for(int i = 0; i < tileTypeIndex; i++) {
TileType tile = TileRegistry[i];
strcpy(ItemRegistry[itemRegistryIndex].name, tile.name);
memcpy(ItemRegistry[itemRegistryIndex].texture, tile.textures, sizeof (tile.textures));
for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) {
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].texture[a], SDL_BLENDMODE_BLEND);
ItemRegistry[itemRegistryIndex].textureOnBelt[a] = ScaleTexture(renderer, tile.textures[a],
TILE_SIZE / 2, TILE_SIZE / 2);
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[a], SDL_BLENDMODE_BLEND);
}
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
itemRegistryIndex++;
}
DIR *dir = opendir("./assets/items");
if (dir) {
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_name[0] == '.') {
continue;
}
registerItem(entry->d_name, renderer);
}
}
}