// // 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 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); } } }