Files
factorygame/items/item.c

233 lines
7.7 KiB
C

//
// Created by bruno on 4/24/25.
//
#include "item.h"
#include "../tiles/tile.h"
#include "../util/util.h"
#include "../player/player.h"
#include "../util/font.h"
#include <dirent.h>
Item ItemRegistry[ITEMREGISTRY_SIZE];
uint16_t itemRegistryIndex = 0;
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 speed = 0.002f; // fraction of tile per tick
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_LEFT ? 1 : 0);
} else if (vert && nH) {
// came off vertical: lane0=left→horizontal.top, lane1=right→horizontal.bottom
newLane = (dir == ORIENT_UP ? 0 : 1);
}
// (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 = IMG_LoadTexture(renderer, texturePath);
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].texture, SDL_BLENDMODE_BLEND);
ItemRegistry[itemRegistryIndex].textureOnBelt = ScaleTexture(renderer, ItemRegistry[itemRegistryIndex].texture,
TILE_SIZE / 2, TILE_SIZE / 2);
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt, SDL_BLENDMODE_BLEND);
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
itemRegistryIndex++;
}
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;
int dir = tileMap[item.tileY][item.tileX].direction;
int offset = item.offset * TILE_SIZE;
int dx = 0, dy = 0; // Direction vector
switch (dir) {
case ORIENT_LEFT_DOWN:
dx = -1;
dy = 1;
break;
case ORIENT_LEFT:
dx = -1;
dy = 0;
break;
case ORIENT_LEFT_UP:
dx = -1;
dy = -1;
break;
case ORIENT_UP:
dx = 0;
dy = -1;
break;
case ORIENT_RIGHT_UP:
dx = 1;
dy = -1;
break;
case ORIENT_RIGHT:
dx = 1;
dy = 0;
break;
case ORIENT_RIGHT_DOWN:
dx = 1;
dy = 1;
break;
case ORIENT_DOWN:
dx = 0;
dy = 1;
break;
default:
break;
}
// Main offset along belt direction
int xOffset = (offset * dx) % TILE_SIZE;
int yOffset = (offset * dy) % TILE_SIZE;
// Perpendicular vector: (dy, -dx)
float perpX = dy;
float perpY = -dx;
float length = sqrtf(perpX * perpX + perpY * perpY);
if (length != 0) {
perpX /= length;
perpY /= length;
}
// Lane offset distance
float laneOffset = (lane == 1 ? 1.0f : -1.0f);
xOffset += (int) (perpX * laneOffset * (TILE_SIZE / 2));
yOffset += (int) (perpY * laneOffset * (TILE_SIZE / 2));
rect.x += xOffset;
rect.y += yOffset;
rect.w = TILE_SIZE / 2;
rect.h = TILE_SIZE / 2;
adjustRect(&rect);
SDL_Rect rectA = {0};
rectA.x = item.tileX * TILE_SIZE;
rectA.y = item.tileY * TILE_SIZE;
rectA.w = TILE_SIZE;
rectA.h = TILE_SIZE;
char tempStr[20];
sprintf(tempStr, "L%d\n%f\n%d\n%d", 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, NULL, &rect);
SDL_Texture *oldRenderTarget = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, NULL);
renderText(renderer, fonts[3], tempStr, rectA.x, rectA.y);
SDL_SetRenderTarget(renderer, oldRenderTarget);
}
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) {
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);
}
}
}