665 lines
24 KiB
C
665 lines
24 KiB
C
//
|
|
// Created by bruno on 4/24/25.
|
|
//
|
|
|
|
#include <dirent.h>
|
|
#include "tile.h"
|
|
#include "../player/player.h"
|
|
#include "furnace.h"
|
|
#include "../util/atlas.h"
|
|
#include "../util/font.h"
|
|
#include "miner.h"
|
|
#include "turret.h"
|
|
#include "../util/perlin.h"
|
|
#include "../util/button.h"
|
|
#include "../util/audio.h"
|
|
#include "ammoCrafter.h"
|
|
#include "wiredrawer.h"
|
|
#include "core.h"
|
|
|
|
MiniRect enemySpawn;
|
|
MiniRect playerCore;
|
|
SDL_Rect viewport;
|
|
|
|
uint16_t DISPLAY_MAP_WIDTH = 30;
|
|
uint16_t DISPLAY_MAP_HEIGHT = 16;
|
|
|
|
uint16_t DISPLAY_WIDTH = 30 * TILE_SIZE;
|
|
uint16_t DISPLAY_HEIGHT = 16 * TILE_SIZE;
|
|
|
|
void setTileView(uint16_t w, uint16_t h) {
|
|
DISPLAY_MAP_WIDTH = w;
|
|
DISPLAY_MAP_HEIGHT = h;
|
|
DISPLAY_WIDTH = DISPLAY_MAP_WIDTH * TILE_SIZE;
|
|
DISPLAY_HEIGHT = DISPLAY_MAP_HEIGHT * TILE_SIZE;
|
|
screenRect.x = 0;
|
|
screenRect.y = 0;
|
|
screenRect.w = DISPLAY_WIDTH;
|
|
screenRect.h = DISPLAY_HEIGHT;
|
|
SDL_RenderSetLogicalSize(mainRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
|
SDL_SetWindowSize(window, DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
|
viewport = screenRect;
|
|
SDL_RenderSetViewport(mainRenderer, &viewport);
|
|
SDL_SetWindowPosition(window, 0, 0);
|
|
audioData.maxPanDistance = DISPLAY_WIDTH / 2;
|
|
|
|
SDL_DestroyTexture(hudTexture);
|
|
SDL_DestroyTexture(entityTexture);
|
|
SDL_DestroyTexture(itemsTexture);
|
|
SDL_DestroyTexture(tilesTexture);
|
|
SDL_DestroyTexture(backgroundTexture);
|
|
|
|
|
|
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);
|
|
|
|
|
|
itemsTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
|
screenRect.h);
|
|
tilesTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
|
screenRect.h);
|
|
SDL_SetTextureBlendMode(tilesTexture, SDL_BLENDMODE_BLEND);
|
|
SDL_SetTextureBlendMode(itemsTexture, SDL_BLENDMODE_BLEND);
|
|
backgroundTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
|
screenRect.w,
|
|
screenRect.h);
|
|
PlayerRect.x = (DISPLAY_WIDTH / 2) - (PlayerRect.w / 2);
|
|
PlayerRect.y = (DISPLAY_HEIGHT / 2) - (PlayerRect.h / 2);
|
|
initButtons();
|
|
}
|
|
|
|
int scrollFrame = 0;
|
|
unsigned long beltFrames = 0;
|
|
|
|
TileArray neededUpdates;
|
|
|
|
int add_tile(TileArray *arr, MiniRect t) {
|
|
if (arr->activeCount >= MAX_TILES) return 0;
|
|
arr->tiles[arr->activeCount] = t;
|
|
arr->activeCount++;
|
|
return arr->activeCount - 1;
|
|
}
|
|
|
|
void remove_tile(TileArray *arr, int index) {
|
|
if (index < 0 || index >= arr->activeCount) return;
|
|
arr->activeCount--;
|
|
arr->tiles[index] = arr->tiles[arr->activeCount]; // swap with last active
|
|
}
|
|
|
|
|
|
SDL_Texture *backgroundTexture;
|
|
SDL_Texture *tilesTexture;
|
|
SDL_Texture *itemsTexture;
|
|
|
|
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
|
|
|
BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH];
|
|
|
|
uint16_t tileTypeIndex = 0;
|
|
uint16_t backgroundTileTypeIndex = 0;
|
|
|
|
TileTypeReg TileRegistry[TILEREGISTRY_SIZE];
|
|
BackgroundTileType BackgroundTileRegistry[TILEREGISTRY_SIZE];
|
|
|
|
|
|
void generateTestMap() {
|
|
for (int y = 0; y < DISPLAY_MAP_HEIGHT; y++) {
|
|
for (int x = 0; x < DISPLAY_MAP_WIDTH; x++) {
|
|
Tile tile = {0};
|
|
tile.rect.x = x;
|
|
tile.rect.y = y;
|
|
tileMap[y][x] = tile;
|
|
}
|
|
}
|
|
|
|
for (int x = 0; x < MAP_WIDTH; x += 1) {
|
|
for (int y = 0; y < MAP_HEIGHT; y += 1) {
|
|
|
|
tileMap[y][x].type = TYPE_BELT;
|
|
tileMap[y][x].miscVal = 0;
|
|
//tileMap[y][x].direction = ((x + y) % 4 * 2) + 1;
|
|
//tileMap[y][x].direction = 5;
|
|
tileMap[y][x].direction = (rand() % 4 * 2) + 1;
|
|
}
|
|
}
|
|
|
|
uint8_t type = 0;
|
|
for (int x = 142; x < 154; x += 3) {
|
|
for (int y = 80; y < 94; y += 3) {
|
|
putItem(x, y, type++ % ITEMREGISTRY_SIZE, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void registerTile(char fname[20], SDL_Renderer *renderer) {
|
|
|
|
char name[21];
|
|
|
|
// Load animation frames
|
|
int frame = 0;
|
|
ItemType indexTile = 0;
|
|
char texturePath[80];
|
|
|
|
if (sscanf(fname, "%d_%20[^_]_%d.png", &indexTile, name, &frame) == 3) {
|
|
// Success: you now have index, fname, and frame
|
|
} else {
|
|
fprintf(stderr, "Invalid format: %s\n", fname);
|
|
}
|
|
strcpy(TileRegistry[indexTile].name, name);
|
|
snprintf(texturePath, sizeof(texturePath), "./assets/tiles/%s", fname);
|
|
|
|
SDL_Texture *texture = IMG_LoadTexture(renderer, texturePath);
|
|
if (!texture) {
|
|
// Stop loading frames if the first one fails, or after all valid ones are added
|
|
if (frame == 0) {
|
|
fprintf(stderr, "Failed to load tile texture %s: %s\n", texturePath, IMG_GetError());
|
|
}
|
|
}
|
|
|
|
for (int o = 0; o < ORIENT_DIRECTION_COUNT; o++) {
|
|
SDL_Texture *textures[ORIENT_DIRECTION_COUNT] = {
|
|
NULL,
|
|
texture,
|
|
NULL,
|
|
createRotatedTexture(renderer, texture, 90),
|
|
NULL,
|
|
createFlippedTexture(renderer, texture, SDL_FLIP_HORIZONTAL),
|
|
NULL,
|
|
createRotatedTexture(renderer, texture, 270)
|
|
};
|
|
|
|
// printf("Bound %s to %d orient %s\n", fname, indexTile, OrientStrings[o]);
|
|
SDL_SetTextureBlendMode(textures[o], SDL_BLENDMODE_BLEND);
|
|
TileRegistry[indexTile].animation.atlasRects[o][frame] = allocate_32x32(textures[o], renderer);
|
|
}
|
|
|
|
//printf("Bound %s to %d\n", fname, indexTile);
|
|
TileRegistry[indexTile].type = indexTile;
|
|
TileRegistry[indexTile].maxHealth = 200;
|
|
TileRegistry[indexTile].animation.frameCount = frame + 1;
|
|
TileRegistry[indexTile].animation.divisor = 1;
|
|
|
|
TileRegistry[indexTile].type = tileTypeIndex;
|
|
TileRegistry[indexTile].breakTime = 15;
|
|
TileRegistry[indexTile].itemMoves = false;
|
|
TileRegistry[indexTile].walkable = false;
|
|
TileRegistry[indexTile].needsTicks = false;
|
|
TileRegistry[indexTile].updateTileCallback = NULL;
|
|
|
|
if (indexTile + 1 > tileTypeIndex) {
|
|
tileTypeIndex = indexTile + 1;
|
|
}
|
|
}
|
|
|
|
|
|
void registerBackgroundTile(char fname[20], SDL_Renderer *renderer) {
|
|
char name[21];
|
|
|
|
// Load animation frames
|
|
int frame = 0;
|
|
int indexBgTile = 0;
|
|
char texturePath[80];
|
|
|
|
if (sscanf(fname, "%d_%20[^_]_%d.png", &indexBgTile, name, &frame) == 3) {
|
|
// Success: you now have index, fname, and frame
|
|
} else {
|
|
fprintf(stderr, "Invalid format: %s\n", fname);
|
|
}
|
|
strcpy(BackgroundTileRegistry[indexBgTile].name, name);
|
|
snprintf(texturePath, sizeof(texturePath), "./assets/backgrounds/%s", fname);
|
|
SDL_Texture *texture = IMG_LoadTexture(renderer, texturePath);
|
|
if (!texture) {
|
|
if (frame == 0) {
|
|
fprintf(stderr, "Failed to load background texture %s: %s\n", texturePath, IMG_GetError());
|
|
}
|
|
}
|
|
|
|
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
|
|
|
|
//printf("Bound %s to %d\n", fname, indexBgTile);
|
|
|
|
BackgroundTileRegistry[indexBgTile].animation.atlasRects[frame] = allocate_32x32(texture, renderer);
|
|
|
|
BackgroundTileRegistry[indexBgTile].type = indexBgTile;
|
|
BackgroundTileRegistry[indexBgTile].animation.frameCount = frame + 1;
|
|
BackgroundTileRegistry[indexBgTile].animation.divisor = 1;
|
|
BackgroundTileRegistry[indexBgTile].walkable = true;
|
|
|
|
if (indexBgTile + 1 > backgroundTileTypeIndex) {
|
|
backgroundTileTypeIndex = indexBgTile + 1;
|
|
}
|
|
}
|
|
|
|
void loadTiles(SDL_Renderer *renderer) {
|
|
DIR *dir = opendir("./assets/tiles");
|
|
if (!dir) {
|
|
perror("Failed to open tiles directory");
|
|
return;
|
|
}
|
|
|
|
char *baseNames[MAX_BASE_NAMES];
|
|
int baseNameCount = 0;
|
|
|
|
struct dirent *entry;
|
|
while ((entry = readdir(dir))) {
|
|
char *dot = strrchr(entry->d_name, '.');
|
|
if (!dot || strcmp(dot, ".png") != 0) continue;
|
|
|
|
// Check if baseName already stored
|
|
int found = 0;
|
|
for (int i = 0; i < baseNameCount; ++i) {
|
|
if (strcmp(baseNames[i], entry->d_name) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found && baseNameCount < MAX_BASE_NAMES) {
|
|
baseNames[baseNameCount++] = strdup(entry->d_name); // Only store base, not full file name
|
|
}
|
|
}
|
|
closedir(dir);
|
|
|
|
qsort(baseNames, baseNameCount, sizeof(char *), compareStrings);
|
|
|
|
// Call registerTile on each base name
|
|
for (int i = 0; i < baseNameCount; ++i) {
|
|
char fileName[64];
|
|
snprintf(fileName, sizeof(fileName), "%s", baseNames[i]);
|
|
registerTile(fileName, renderer);
|
|
free(baseNames[i]);
|
|
}
|
|
generateBeltFrames(renderer);
|
|
|
|
}
|
|
|
|
|
|
void loadBackgroundTiles(SDL_Renderer *renderer) {
|
|
DIR *dir = opendir("./assets/backgrounds");
|
|
if (!dir) {
|
|
perror("Failed to open backgrounds directory");
|
|
return;
|
|
}
|
|
|
|
char *baseNames[MAX_BASE_NAMES];
|
|
int baseNameCount = 0;
|
|
|
|
struct dirent *entry;
|
|
while ((entry = readdir(dir))) {
|
|
char *dot = strrchr(entry->d_name, '.');
|
|
if (!dot || strcmp(dot, ".png") != 0) continue;
|
|
|
|
// Check if baseName already stored
|
|
int found = 0;
|
|
for (int i = 0; i < baseNameCount; ++i) {
|
|
if (strcmp(baseNames[i], entry->d_name) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found && baseNameCount < MAX_BASE_NAMES) {
|
|
baseNames[baseNameCount++] = strdup(entry->d_name); // Only store base, not full file name
|
|
}
|
|
}
|
|
closedir(dir);
|
|
|
|
qsort(baseNames, baseNameCount, sizeof(char *), compareStrings);
|
|
|
|
// Call registerBackgroundTile on each base name
|
|
for (int i = 0; i < baseNameCount; ++i) {
|
|
char fileName[64];
|
|
snprintf(fileName, sizeof(fileName), "%s", baseNames[i]);
|
|
registerBackgroundTile(fileName, renderer);
|
|
free(baseNames[i]);
|
|
}
|
|
}
|
|
|
|
void preSetupTiles() {
|
|
TileRegistry[TYPE_MINER].animation.startFrame = 1;
|
|
TileRegistry[TYPE_FURNACE].animation.divisor = 8;
|
|
|
|
TileRegistry[TYPE_WIRECRAFTER].animation.divisor = 8;
|
|
TileRegistry[TYPE_SPLITTER].animation.divisor = 8;
|
|
TileRegistry[TYPE_AMMOCRAFTER].animation.divisor = 8;
|
|
|
|
TileRegistry[TYPE_CORE].animation.divisor = 8;
|
|
BackgroundTileRegistry[BGType_WATER_DEEP].animation.divisor = 16;
|
|
BackgroundTileRegistry[BGType_ENEMY_FLOOR].animation.divisor = 16;
|
|
BackgroundTileRegistry[BGType_WATER_SHALLOW].animation.divisor = 12;
|
|
BackgroundTileRegistry[BGType_GRASS_FLOWER0].animation.divisor = 16;
|
|
BackgroundTileRegistry[BGType_GRASS_FLOWER1].animation.divisor = 16;
|
|
BackgroundTileRegistry[BGType_GRASS_FLOWER2].animation.divisor = 16;
|
|
}
|
|
|
|
void setupTiles() {
|
|
TileRegistry[TYPE_AIR].breakTime = 0;
|
|
TileRegistry[TYPE_BELT].itemMoves = true;
|
|
for (uint16_t i = 0; i < ItemSlotCount; i++) {
|
|
TileRegistry[TYPE_BELT].outputLane[i] = true;
|
|
}
|
|
for (uint16_t l = 0; l < 2; l++) {
|
|
for (ItemType i = 0; i < itemRegistryIndex; i++) {
|
|
TileRegistry[TYPE_BELT].allowedInItems[l][i] = true;
|
|
}
|
|
}
|
|
for (ItemType i = 0; i < itemRegistryIndex; i++) {
|
|
TileRegistry[TYPE_SPLITTER].allowedInItems[0][i] = true;
|
|
}
|
|
TileRegistry[TYPE_SPLITTER].outputLane[0] = true;
|
|
TileRegistry[TYPE_SPLITTER].needsTicks = true;
|
|
TileRegistry[TYPE_SPLITTER].walkable = true;
|
|
TileRegistry[TYPE_SPLITTER].allDir = true;
|
|
|
|
TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1;
|
|
TileRegistry[TYPE_FURNACE].animation.startFrame = 1;
|
|
TileRegistry[TYPE_FURNACE].needsTicks = true;
|
|
TileRegistry[TYPE_BELT].needsTicks = true;
|
|
TileRegistry[TYPE_BELT].walkable = true;
|
|
TileRegistry[TYPE_MINER].needsTicks = true;
|
|
TileRegistry[TYPE_MINER].outputLane[MINER_OUTPUT_SLOT] = 1;
|
|
TileRegistry[TYPE_AIR].walkable = true;
|
|
|
|
TileRegistry[TYPE_TURRET].needsTicks = true;
|
|
for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) {
|
|
if (AmmoDamages[i] > 0)
|
|
TileRegistry[TYPE_TURRET].allowedInItems[TURRET_AMMO_INPUT_SLOT][i] = true;
|
|
}
|
|
|
|
|
|
BackgroundTileRegistry[BGType_WATER_SHALLOW].walkable = false;
|
|
BackgroundTileRegistry[BGType_WATER_DEEP].walkable = false;
|
|
|
|
initFurnaceTile();
|
|
initWireDrawerTile();
|
|
initAmmoCrafterTile();
|
|
initCoreTile();
|
|
}
|
|
|
|
uint16_t getBreakTime(int type) {
|
|
if (type >= tileTypeIndex) {
|
|
return 0;
|
|
}
|
|
return TileRegistry[type].breakTime;
|
|
}
|
|
|
|
void initTiles() {
|
|
itemsTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
|
screenRect.h);
|
|
tilesTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
|
screenRect.h);
|
|
backgroundTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
|
screenRect.w,
|
|
screenRect.h);
|
|
SDL_SetTextureBlendMode(itemsTexture, SDL_BLENDMODE_BLEND);
|
|
SDL_SetTextureBlendMode(tilesTexture, SDL_BLENDMODE_BLEND);
|
|
}
|
|
|
|
void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
|
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
|
|
|
int tileSize = TILE_SIZE;
|
|
|
|
int minTileX = (playerRect.x / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2) - 1;
|
|
int maxTileX = (playerRect.x / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) + 1;
|
|
int minTileY = (playerRect.y / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2) - 1;
|
|
int maxTileY = (playerRect.y / TILE_SIZE) + (DISPLAY_MAP_HEIGHT / 2) + 1;
|
|
|
|
int scrollSpeed = 1; // pixels per step
|
|
int scrollDelay = 1; // frames between steps
|
|
|
|
if (beltFrames++ % scrollDelay == 0) {
|
|
scrollFrame += scrollSpeed;
|
|
}
|
|
|
|
// --- Render background tiles ---
|
|
SDL_SetRenderTarget(renderer, backgroundTexture);
|
|
SDL_RenderClear(renderer);
|
|
|
|
for (int y = minTileY; y < maxTileY; y++) {
|
|
if (y < 0 || y >= MAP_HEIGHT) continue;
|
|
for (int x = minTileX; x < maxTileX; x++) {
|
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
|
|
|
SDL_Rect dstRect = {
|
|
.x = x * TILE_SIZE,
|
|
.y = y * TILE_SIZE,
|
|
.w = TILE_SIZE,
|
|
.h = TILE_SIZE
|
|
};
|
|
adjustRect(&dstRect, playerRect);
|
|
|
|
BackgroundTile bt = backgroundMap[y][x];
|
|
if (bt.type > BGType_END) {
|
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
|
SDL_RenderFillRect(renderer, &dstRect);
|
|
printf("Error on tile %d, %d\n", x, y);
|
|
backgroundMap[y][x].type = BGType_PLATINUM_ORE;
|
|
} else {
|
|
SDL_Rect atlRect = BackgroundTileRegistry[bt.type].animation.atlasRects[
|
|
(animationStep / BackgroundTileRegistry[bt.type].animation.divisor) %
|
|
BackgroundTileRegistry[bt.type].animation.frameCount];
|
|
if (atlRect.w != 0 && atlRect.h != 0) {
|
|
SDL_RenderCopy(renderer, atlasTexture, &atlRect, &dstRect);
|
|
//SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_SetRenderTarget(renderer, tilesTexture);
|
|
SDL_RenderClear(renderer);
|
|
for (int y = minTileY; y < maxTileY; y++) {
|
|
if (y < 0 || y >= MAP_HEIGHT) continue;
|
|
for (int x = minTileX; x < maxTileX; x++) {
|
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
|
|
|
SDL_Rect dstRect = {
|
|
.x = x * TILE_SIZE,
|
|
.y = y * TILE_SIZE,
|
|
.w = TILE_SIZE,
|
|
.h = TILE_SIZE
|
|
};
|
|
adjustRect(&dstRect, playerRect);
|
|
|
|
Tile t = tileMap[y][x];
|
|
switch (t.type) {
|
|
case TYPE_AIR:
|
|
break;
|
|
case TYPE_BELT:
|
|
renderBelt(x, y, tileSize, tileSize, t.direction, playerRect, renderer);
|
|
break;
|
|
default: {
|
|
char animationFrame = ((animationStep / TileRegistry[t.type].animation.divisor) %
|
|
(TileRegistry[t.type].animation.frameCount -
|
|
TileRegistry[t.type].animation.startFrame)) +
|
|
TileRegistry[t.type].animation.startFrame;
|
|
if (t.fixedFrame > 0) {
|
|
animationFrame = t.fixedFrame - 1;
|
|
}
|
|
SDL_Rect atlRect = TileRegistry[t.type].animation.atlasRects[t.direction][animationFrame];
|
|
if (atlRect.w == 0 || atlRect.h == 0) {
|
|
atlRect = TileRegistry[t.type].animation.atlasRects[ORIENT_LEFT][
|
|
animationFrame];
|
|
}
|
|
if (atlRect.w != 0 && atlRect.h != 0) {
|
|
SDL_RenderCopy(renderer, atlasTexture, &atlRect, &dstRect);
|
|
if (t.health < TileRegistry[t.type].maxHealth) {
|
|
char healthStr[12];
|
|
snprintf(healthStr, 12, "%d/%d", t.health, TileRegistry[t.type].maxHealth);
|
|
renderText(renderer, fonts[3], healthStr, dstRect.x, dstRect.y);
|
|
}
|
|
// if (t.health < TileRegistry[t.type].maxHealth) {
|
|
// SDL_Color tileHealthColor = {(t.health / TileRegistry[t.type].maxHealth ) * 255, (TileRegistry[t.type].maxHealth / t.health) * 255, 0, 255};
|
|
// renderBar(mainRenderer, x * TILE_SIZE, (y * TILE_SIZE) + (TILE_SIZE / 2), TILE_SIZE, 8,
|
|
// TileRegistry[t.type].maxHealth, t.health, tileHealthColor, 4);
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_SetRenderTarget(renderer, itemsTexture);
|
|
SDL_RenderClear(renderer);
|
|
for (int y = minTileY; y < maxTileY; y++) {
|
|
if (y < 0 || y >= MAP_HEIGHT) continue;
|
|
for (int x = minTileX; x < maxTileX; x++) {
|
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
|
|
|
Tile t = tileMap[y][x];
|
|
if (debugMode) {
|
|
char locChar[20];
|
|
sprintf(locChar, "X:%d\nY:%d", x, y);
|
|
SDL_Rect dstRect = {
|
|
.x = x * TILE_SIZE,
|
|
.y = y * TILE_SIZE,
|
|
.w = TILE_SIZE,
|
|
.h = TILE_SIZE
|
|
};
|
|
adjustRect(&dstRect, playerRect);
|
|
renderText(renderer, fonts[4], locChar, dstRect.x, dstRect.y);
|
|
}
|
|
if (t.type == TYPE_BELT || itemViewing) {
|
|
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
|
if (t.items[lane].type != 0) {
|
|
renderItem(t.items[lane], renderer, lane, playerRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_SetRenderTarget(renderer, oldTarget);
|
|
}
|
|
|
|
bool isWalkable(MiniRect tileCoords) {
|
|
if (tileCoords.x < 0 || tileCoords.x >= MAP_WIDTH || tileCoords.y < 0 || tileCoords.y >= MAP_HEIGHT) {
|
|
return false;
|
|
}
|
|
BackgroundTileType bgt = BackgroundTileRegistry[backgroundMap[tileCoords.y][tileCoords.x].type];
|
|
TileTypeReg fgt = TileRegistry[tileMap[tileCoords.y][tileCoords.x].type];
|
|
|
|
return bgt.walkable && fgt.walkable;
|
|
}
|
|
|
|
void updateTiles() {
|
|
|
|
}
|
|
|
|
// Main generator:
|
|
void genInitMap() {
|
|
const double terrainScale = 2;
|
|
const double humidityScale = 1;
|
|
const double oreScale = 2;
|
|
const int terrainOct = 4;
|
|
const int humidityOct = 4;
|
|
const int oreOct = 4;
|
|
|
|
int seedX = rand();
|
|
int seedY = rand();
|
|
int seedN = rand();
|
|
|
|
// Min/max trackers
|
|
double terrainMin = 1e9, terrainMax = -1e9;
|
|
double humidityMin = 1e9, humidityMax = -1e9;
|
|
double oreNrmMin = 1e9, oreNrmMax = -1e9;
|
|
for (uint16_t y = 0; y < MAP_HEIGHT; y++) {
|
|
for (uint16_t x = 0; x < MAP_WIDTH; x++) {
|
|
double terrain = pnoise2d(x + 1000 + seedX,
|
|
y + 1000 + seedY,
|
|
terrainScale, terrainOct, seedN);
|
|
double humidity = pnoise2d(x + seedX,
|
|
y + seedY,
|
|
humidityScale, humidityOct, seedN);
|
|
double oreNrm = pnoise2d(x + 9999 + seedX,
|
|
y + 1111 + seedY,
|
|
oreScale, oreOct, seedN);
|
|
|
|
// Track min/max
|
|
if (terrain < terrainMin) terrainMin = terrain;
|
|
if (terrain > terrainMax) terrainMax = terrain;
|
|
|
|
if (humidity < humidityMin) humidityMin = humidity;
|
|
if (humidity > humidityMax) humidityMax = humidity;
|
|
|
|
if (oreNrm < oreNrmMin) oreNrmMin = oreNrm;
|
|
if (oreNrm > oreNrmMax) oreNrmMax = oreNrm;
|
|
|
|
// [Same as your original terrain generation logic...]
|
|
BackgroundType baseType = BGType_COBBLE0;
|
|
if (terrain < 0.30) {
|
|
baseType = (humidity < 0.5) ? BGType_WATER_SHALLOW : BGType_WATER_DEEP;
|
|
} else if (terrain < 0.35) {
|
|
if (humidity < 0.3) baseType = BGType_SAND4;
|
|
else if (humidity < 0.6) baseType = BGType_SAND2;
|
|
else baseType = BGType_SAND7;
|
|
} else if (terrain < 0.7) {
|
|
double grassVal = (terrain - 0.35) / (0.70 - 0.35);
|
|
int idx = (int) (grassVal * 3.0);
|
|
if (idx >= 4) idx = 3;
|
|
if (humidity > 0.6 && ((rand() & 0xFF) < 10)) {
|
|
int flowerIdx = rand() % 4;
|
|
baseType = (BackgroundType) (BGType_GRASS_FLOWER0 + flowerIdx);
|
|
} else {
|
|
baseType = (BackgroundType) (BGType_GRASS0 + idx);
|
|
}
|
|
} else if (terrain < 0.85) {
|
|
int idx = rand() % 4;
|
|
baseType = (BackgroundType) (BGType_COBBLE0 + idx);
|
|
} else {
|
|
int idx = rand() % 4;
|
|
baseType = (BackgroundType) (BGType_TILES0 + idx);
|
|
}
|
|
|
|
BackgroundType finalType = baseType;
|
|
if (baseType != BGType_WATER_SHALLOW && baseType != BGType_WATER_DEEP) {
|
|
if (oreNrm > 0.86) {
|
|
double sub = (oreNrm - 0.86) / (1.0 - 0.86);
|
|
if (sub < 0.25) finalType = BGType_IRON_ORE;
|
|
else if (sub < 0.50) finalType = BGType_SILVER_ORE;
|
|
else if (sub < 0.80) finalType = BGType_GOLD_ORE;
|
|
else finalType = BGType_PLATINUM_ORE;
|
|
}
|
|
}
|
|
|
|
if (finalType > BGType_END) {
|
|
finalType = BGType_COBBLE0;
|
|
}
|
|
backgroundMap[y][x].type = finalType;
|
|
}
|
|
enemySpawn.x = MAP_WIDTH - 10;
|
|
enemySpawn.y = 10;
|
|
for (int enX = enemySpawn.x - 5; enX < enemySpawn.x + 6; enX++) {
|
|
for (int enY = enemySpawn.y - 5; enY < enemySpawn.y + 6; enY++) {
|
|
backgroundMap[enY][enX].type = BGType_ENEMY_FLOOR;
|
|
}
|
|
}
|
|
playerCore.x = 8;
|
|
playerCore.y = MAP_HEIGHT - 10;
|
|
for (int plX = playerCore.x - 5; plX < playerCore.x + 6; plX++) {
|
|
for (int plY = playerCore.y - 5; plY < playerCore.y + 6; plY++) {
|
|
backgroundMap[plY][plX].type = BGType_TILES0;
|
|
}
|
|
}
|
|
tileMap[playerCore.y][playerCore.x].type = TYPE_CORE;
|
|
tileMap[playerCore.y][playerCore.x].direction = ORIENT_LEFT;
|
|
tileMap[playerCore.y][playerCore.x].health = TileRegistry[TYPE_CORE].maxHealth;
|
|
tileMap[playerCore.y][playerCore.x].fixedFrame = 0;
|
|
tileMap[playerCore.y][playerCore.x].rect = playerCore;
|
|
|
|
}
|
|
|
|
// Debug printout
|
|
printf("Terrain Noise: min = %f, max = %f\n", terrainMin, terrainMax);
|
|
printf("Humidity Noise: min = %f, max = %f\n", humidityMin, humidityMax);
|
|
printf("Ore Normalized: min = %f, max = %f\n", oreNrmMin, oreNrmMax);
|
|
}
|