diff --git a/CMakeLists.txt b/CMakeLists.txt index a5d8ee8..1026f98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ set(SOURCE_FILES entity/entity.h tiles/turret.c tiles/turret.h + util/crafter.c + util/crafter.h ) add_executable(factorygame ${SOURCE_FILES}) diff --git a/assets/items/08-iron_bullet-00.png b/assets/items/08-iron_bullet-00.png new file mode 100644 index 0000000..361f32f Binary files /dev/null and b/assets/items/08-iron_bullet-00.png differ diff --git a/assets/items/10-gold_bullet-00.png b/assets/items/10-gold_bullet-00.png new file mode 100644 index 0000000..80db29b Binary files /dev/null and b/assets/items/10-gold_bullet-00.png differ diff --git a/assets/items/11-platinum_bullet-00.png b/assets/items/11-platinum_bullet-00.png new file mode 100644 index 0000000..7b1e156 Binary files /dev/null and b/assets/items/11-platinum_bullet-00.png differ diff --git a/assets/items/08-log-00.png b/assets/items/12-log-00.png similarity index 100% rename from assets/items/08-log-00.png rename to assets/items/12-log-00.png diff --git a/assets/tiles/04_miner_00.png b/assets/tiles/04_miner_00.png index 7d28435..59775b9 100644 Binary files a/assets/tiles/04_miner_00.png and b/assets/tiles/04_miner_00.png differ diff --git a/assets/tiles/04_miner_01.png b/assets/tiles/04_miner_01.png index 6e68be0..8577b74 100644 Binary files a/assets/tiles/04_miner_01.png and b/assets/tiles/04_miner_01.png differ diff --git a/assets/tiles/04_miner_02.png b/assets/tiles/04_miner_02.png index 98c4e9a..22dab23 100644 Binary files a/assets/tiles/04_miner_02.png and b/assets/tiles/04_miner_02.png differ diff --git a/assets/tiles/04_miner_03.png b/assets/tiles/04_miner_03.png index 5d7d1a8..31dc758 100644 Binary files a/assets/tiles/04_miner_03.png and b/assets/tiles/04_miner_03.png differ diff --git a/assets/tiles/04_miner_04.png b/assets/tiles/04_miner_04.png index 779ed20..3d3ae07 100644 Binary files a/assets/tiles/04_miner_04.png and b/assets/tiles/04_miner_04.png differ diff --git a/assets/tiles/04_miner_05.png b/assets/tiles/04_miner_05.png index c80d002..5eb6328 100644 Binary files a/assets/tiles/04_miner_05.png and b/assets/tiles/04_miner_05.png differ diff --git a/assets/tiles/04_miner_06.png b/assets/tiles/04_miner_06.png index c7b966f..8d85ee8 100644 Binary files a/assets/tiles/04_miner_06.png and b/assets/tiles/04_miner_06.png differ diff --git a/assets/tiles/04_miner_07.png b/assets/tiles/04_miner_07.png index 100482d..5f7063f 100644 Binary files a/assets/tiles/04_miner_07.png and b/assets/tiles/04_miner_07.png differ diff --git a/assets/tiles/04_miner_08.png b/assets/tiles/04_miner_08.png new file mode 100644 index 0000000..f4e90ec Binary files /dev/null and b/assets/tiles/04_miner_08.png differ diff --git a/assets/tiles/04_miner_09.png b/assets/tiles/04_miner_09.png new file mode 100644 index 0000000..5360907 Binary files /dev/null and b/assets/tiles/04_miner_09.png differ diff --git a/assets/tiles/04_miner_10.png b/assets/tiles/04_miner_10.png new file mode 100644 index 0000000..21c703a Binary files /dev/null and b/assets/tiles/04_miner_10.png differ diff --git a/assets/tiles/05_turret_00.png b/assets/tiles/05_turret_00.png index af1f004..21a4b12 100644 Binary files a/assets/tiles/05_turret_00.png and b/assets/tiles/05_turret_00.png differ diff --git a/assets/tiles/05_turret_01.png b/assets/tiles/05_turret_01.png index d191068..1811150 100644 Binary files a/assets/tiles/05_turret_01.png and b/assets/tiles/05_turret_01.png differ diff --git a/assets/tiles/05_turret_02.png b/assets/tiles/05_turret_02.png index c31d987..769e60c 100644 Binary files a/assets/tiles/05_turret_02.png and b/assets/tiles/05_turret_02.png differ diff --git a/assets/tiles/05_turret_03.png b/assets/tiles/05_turret_03.png index 42db6b6..eab1bc6 100644 Binary files a/assets/tiles/05_turret_03.png and b/assets/tiles/05_turret_03.png differ diff --git a/assets/tiles/05_turret_04.png b/assets/tiles/05_turret_04.png index 565bc37..0c27dfd 100644 Binary files a/assets/tiles/05_turret_04.png and b/assets/tiles/05_turret_04.png differ diff --git a/assets/tiles/05_turret_05.png b/assets/tiles/05_turret_05.png new file mode 100644 index 0000000..16ad8a5 Binary files /dev/null and b/assets/tiles/05_turret_05.png differ diff --git a/assets/tiles/05_turret_06.png b/assets/tiles/05_turret_06.png new file mode 100644 index 0000000..fe142a8 Binary files /dev/null and b/assets/tiles/05_turret_06.png differ diff --git a/assets/tiles/05_turret_07.png b/assets/tiles/05_turret_07.png new file mode 100644 index 0000000..3783cd8 Binary files /dev/null and b/assets/tiles/05_turret_07.png differ diff --git a/assets/tiles/05_turret_08.png b/assets/tiles/05_turret_08.png new file mode 100644 index 0000000..a1c1961 Binary files /dev/null and b/assets/tiles/05_turret_08.png differ diff --git a/assets/tiles/05_turret_09.png b/assets/tiles/05_turret_09.png new file mode 100644 index 0000000..e82443c Binary files /dev/null and b/assets/tiles/05_turret_09.png differ diff --git a/assets/tiles/05_turret_10.png b/assets/tiles/05_turret_10.png new file mode 100644 index 0000000..03b59ea Binary files /dev/null and b/assets/tiles/05_turret_10.png differ diff --git a/assets/tiles/05_turret_11.png b/assets/tiles/05_turret_11.png new file mode 100644 index 0000000..d1f13b4 Binary files /dev/null and b/assets/tiles/05_turret_11.png differ diff --git a/assets/tiles/05_turret_12.png b/assets/tiles/05_turret_12.png new file mode 100644 index 0000000..8d1a7c2 Binary files /dev/null and b/assets/tiles/05_turret_12.png differ diff --git a/assets/tiles/05_turret_13.png b/assets/tiles/05_turret_13.png new file mode 100644 index 0000000..2607aa8 Binary files /dev/null and b/assets/tiles/05_turret_13.png differ diff --git a/assets/tiles/05_turret_14.png b/assets/tiles/05_turret_14.png new file mode 100644 index 0000000..1077580 Binary files /dev/null and b/assets/tiles/05_turret_14.png differ diff --git a/assets/tiles/05_turret_15.png b/assets/tiles/05_turret_15.png new file mode 100644 index 0000000..3ce0dcd Binary files /dev/null and b/assets/tiles/05_turret_15.png differ diff --git a/assets/tiles/05_turret_16.png b/assets/tiles/05_turret_16.png new file mode 100644 index 0000000..3ce0dcd Binary files /dev/null and b/assets/tiles/05_turret_16.png differ diff --git a/assets/tiles/05_turret_17.png b/assets/tiles/05_turret_17.png new file mode 100644 index 0000000..308730c Binary files /dev/null and b/assets/tiles/05_turret_17.png differ diff --git a/assets/tiles/05_turret_18.png b/assets/tiles/05_turret_18.png new file mode 100644 index 0000000..7a7e077 Binary files /dev/null and b/assets/tiles/05_turret_18.png differ diff --git a/assets/tiles/05_turret_19.png b/assets/tiles/05_turret_19.png new file mode 100644 index 0000000..9d7ec35 Binary files /dev/null and b/assets/tiles/05_turret_19.png differ diff --git a/assets/tiles/05_turret_20.png b/assets/tiles/05_turret_20.png new file mode 100644 index 0000000..34204c6 Binary files /dev/null and b/assets/tiles/05_turret_20.png differ diff --git a/assets/tiles/05_turret_21.png b/assets/tiles/05_turret_21.png new file mode 100644 index 0000000..65e4d8a Binary files /dev/null and b/assets/tiles/05_turret_21.png differ diff --git a/assets/tiles/05_turret_22.png b/assets/tiles/05_turret_22.png new file mode 100644 index 0000000..c822b4f Binary files /dev/null and b/assets/tiles/05_turret_22.png differ diff --git a/assets/tiles/05_turret_23.png b/assets/tiles/05_turret_23.png new file mode 100644 index 0000000..d90603d Binary files /dev/null and b/assets/tiles/05_turret_23.png differ diff --git a/assets/tiles/05_turret_24.png b/assets/tiles/05_turret_24.png new file mode 100644 index 0000000..ec5d660 Binary files /dev/null and b/assets/tiles/05_turret_24.png differ diff --git a/assets/tiles/05_turret_25.png b/assets/tiles/05_turret_25.png new file mode 100644 index 0000000..8c5d9d9 Binary files /dev/null and b/assets/tiles/05_turret_25.png differ diff --git a/assets/tiles/05_turret_26.png b/assets/tiles/05_turret_26.png new file mode 100644 index 0000000..fb02a83 Binary files /dev/null and b/assets/tiles/05_turret_26.png differ diff --git a/assets/tiles/05_turret_27.png b/assets/tiles/05_turret_27.png new file mode 100644 index 0000000..ce8ce94 Binary files /dev/null and b/assets/tiles/05_turret_27.png differ diff --git a/assets/tiles/05_turret_28.png b/assets/tiles/05_turret_28.png new file mode 100644 index 0000000..3f34a41 Binary files /dev/null and b/assets/tiles/05_turret_28.png differ diff --git a/assets/tiles/05_turret_29.png b/assets/tiles/05_turret_29.png new file mode 100644 index 0000000..9ac4987 Binary files /dev/null and b/assets/tiles/05_turret_29.png differ diff --git a/assets/tiles/05_turret_30.png b/assets/tiles/05_turret_30.png new file mode 100644 index 0000000..e50fca1 Binary files /dev/null and b/assets/tiles/05_turret_30.png differ diff --git a/assets/tiles/05_turret_31.png b/assets/tiles/05_turret_31.png new file mode 100644 index 0000000..bb696cf Binary files /dev/null and b/assets/tiles/05_turret_31.png differ diff --git a/assets/tiles/05_turret_32.png b/assets/tiles/05_turret_32.png new file mode 100644 index 0000000..9d05844 Binary files /dev/null and b/assets/tiles/05_turret_32.png differ diff --git a/assets/tiles/05_turret_33.png b/assets/tiles/05_turret_33.png new file mode 100644 index 0000000..c72472a Binary files /dev/null and b/assets/tiles/05_turret_33.png differ diff --git a/assets/tiles/05_turret_34.png b/assets/tiles/05_turret_34.png new file mode 100644 index 0000000..0e6e4c3 Binary files /dev/null and b/assets/tiles/05_turret_34.png differ diff --git a/assets/tiles/05_turret_35.png b/assets/tiles/05_turret_35.png new file mode 100644 index 0000000..6b60c29 Binary files /dev/null and b/assets/tiles/05_turret_35.png differ diff --git a/assets/tiles/05_turret_36.png b/assets/tiles/05_turret_36.png new file mode 100644 index 0000000..70e2f5d Binary files /dev/null and b/assets/tiles/05_turret_36.png differ diff --git a/assets/tiles/05_turret_37.png b/assets/tiles/05_turret_37.png new file mode 100644 index 0000000..1e3c996 Binary files /dev/null and b/assets/tiles/05_turret_37.png differ diff --git a/assets/tiles/05_turret_38.png b/assets/tiles/05_turret_38.png new file mode 100644 index 0000000..721cda1 Binary files /dev/null and b/assets/tiles/05_turret_38.png differ diff --git a/assets/tiles/05_turret_39.png b/assets/tiles/05_turret_39.png new file mode 100644 index 0000000..a0256e0 Binary files /dev/null and b/assets/tiles/05_turret_39.png differ diff --git a/assets/tiles/05_turret_40.png b/assets/tiles/05_turret_40.png new file mode 100644 index 0000000..721cda1 Binary files /dev/null and b/assets/tiles/05_turret_40.png differ diff --git a/assets/tiles/05_turret_41.png b/assets/tiles/05_turret_41.png new file mode 100644 index 0000000..a0256e0 Binary files /dev/null and b/assets/tiles/05_turret_41.png differ diff --git a/assets/tiles/06_splitter_00.png b/assets/tiles/06_splitter_00.png new file mode 100644 index 0000000..c425521 Binary files /dev/null and b/assets/tiles/06_splitter_00.png differ diff --git a/assets/tiles/06_splitter_01.png b/assets/tiles/06_splitter_01.png new file mode 100644 index 0000000..507ffa1 Binary files /dev/null and b/assets/tiles/06_splitter_01.png differ diff --git a/assets/tiles/06_splitter_02.png b/assets/tiles/06_splitter_02.png new file mode 100644 index 0000000..647a138 Binary files /dev/null and b/assets/tiles/06_splitter_02.png differ diff --git a/assets/tiles/06_splitter_03.png b/assets/tiles/06_splitter_03.png new file mode 100644 index 0000000..d7760fa Binary files /dev/null and b/assets/tiles/06_splitter_03.png differ diff --git a/assets/tiles/06_splitter_04.png b/assets/tiles/06_splitter_04.png new file mode 100644 index 0000000..7e9c47c Binary files /dev/null and b/assets/tiles/06_splitter_04.png differ diff --git a/assets/tiles/12_core_00.png b/assets/tiles/12_core_00.png new file mode 100644 index 0000000..eba6f19 Binary files /dev/null and b/assets/tiles/12_core_00.png differ diff --git a/assets/tiles/12_core_01.png b/assets/tiles/12_core_01.png new file mode 100644 index 0000000..1a9c453 Binary files /dev/null and b/assets/tiles/12_core_01.png differ diff --git a/assets/tiles/12_core_02.png b/assets/tiles/12_core_02.png new file mode 100644 index 0000000..1d7177a Binary files /dev/null and b/assets/tiles/12_core_02.png differ diff --git a/assets/tiles/12_core_03.png b/assets/tiles/12_core_03.png new file mode 100644 index 0000000..7baa29b Binary files /dev/null and b/assets/tiles/12_core_03.png differ diff --git a/assets/tiles/12_core_04.png b/assets/tiles/12_core_04.png new file mode 100644 index 0000000..7baa29b Binary files /dev/null and b/assets/tiles/12_core_04.png differ diff --git a/assets/tiles/12_core_05.png b/assets/tiles/12_core_05.png new file mode 100644 index 0000000..30f98ad Binary files /dev/null and b/assets/tiles/12_core_05.png differ diff --git a/assets/tiles/12_core_06.png b/assets/tiles/12_core_06.png new file mode 100644 index 0000000..2475d73 Binary files /dev/null and b/assets/tiles/12_core_06.png differ diff --git a/assets/tiles/12_core_07.png b/assets/tiles/12_core_07.png new file mode 100644 index 0000000..5c48712 Binary files /dev/null and b/assets/tiles/12_core_07.png differ diff --git a/assets/tiles/12_core_08.png b/assets/tiles/12_core_08.png new file mode 100644 index 0000000..f0379ed Binary files /dev/null and b/assets/tiles/12_core_08.png differ diff --git a/assets/tiles/12_core_09.png b/assets/tiles/12_core_09.png new file mode 100644 index 0000000..c33b0ba Binary files /dev/null and b/assets/tiles/12_core_09.png differ diff --git a/assets/tiles/12_core_10.png b/assets/tiles/12_core_10.png new file mode 100644 index 0000000..beaf03f Binary files /dev/null and b/assets/tiles/12_core_10.png differ diff --git a/assets/tiles/12_core_11.png b/assets/tiles/12_core_11.png new file mode 100644 index 0000000..4814053 Binary files /dev/null and b/assets/tiles/12_core_11.png differ diff --git a/assets/tiles/12_core_12.png b/assets/tiles/12_core_12.png new file mode 100644 index 0000000..1a9c453 Binary files /dev/null and b/assets/tiles/12_core_12.png differ diff --git a/assets/tiles/12_core_13.png b/assets/tiles/12_core_13.png new file mode 100644 index 0000000..1d7177a Binary files /dev/null and b/assets/tiles/12_core_13.png differ diff --git a/assets/tiles/12_core_14.png b/assets/tiles/12_core_14.png new file mode 100644 index 0000000..7baa29b Binary files /dev/null and b/assets/tiles/12_core_14.png differ diff --git a/assets/tiles/12_core_15.png b/assets/tiles/12_core_15.png new file mode 100644 index 0000000..30f98ad Binary files /dev/null and b/assets/tiles/12_core_15.png differ diff --git a/assets/tiles/12_core_16.png b/assets/tiles/12_core_16.png new file mode 100644 index 0000000..2475d73 Binary files /dev/null and b/assets/tiles/12_core_16.png differ diff --git a/assets/tiles/12_core_17.png b/assets/tiles/12_core_17.png new file mode 100644 index 0000000..5c48712 Binary files /dev/null and b/assets/tiles/12_core_17.png differ diff --git a/assets/tiles/12_core_18.png b/assets/tiles/12_core_18.png new file mode 100644 index 0000000..c33b0ba Binary files /dev/null and b/assets/tiles/12_core_18.png differ diff --git a/assets/tiles/12_core_19.png b/assets/tiles/12_core_19.png new file mode 100644 index 0000000..beaf03f Binary files /dev/null and b/assets/tiles/12_core_19.png differ diff --git a/assets/tiles/12_core_20.png b/assets/tiles/12_core_20.png new file mode 100644 index 0000000..4814053 Binary files /dev/null and b/assets/tiles/12_core_20.png differ diff --git a/entity/entity.c b/entity/entity.c index ba5d3e1..10bc0b4 100644 --- a/entity/entity.c +++ b/entity/entity.c @@ -8,6 +8,7 @@ #include "../player/player.h" #include "../util/pathfinding.h" #include "../util/font.h" +#include "../util/audio.h" EntityArray entities; @@ -29,11 +30,12 @@ void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect) { SDL_RenderCopy(renderer, atlasTexture, &entType.animation.atlasRects[animationFrame], &renderRect); char healthStr[12]; snprintf(healthStr, 12, "%d/%d", ent->health, entType.maxHealth); - renderText(renderer, fonts[2], healthStr, renderRect.x, renderRect.y); + renderText(renderer, fonts[3], healthStr, renderRect.x, renderRect.y); } SDL_SetRenderTarget(renderer, oldTarget); } -void updateEntities() { + +void updateEntities(Player *plr) { for (int i = 0; i < entities.activeCount; i++) { Entity *ent = &entities.entities[i]; EntityTypeReg entT = EntityRegistry[ent->type]; @@ -48,6 +50,35 @@ void updateEntities() { bool atTarget = ent->tileRect.x == ent->target.x && ent->tileRect.y == ent->target.y; + if (animationStep >= ent->entityNextTick) { + if (sqrt(pow(abs(plr->tileRect.x - ent->tileRect.x), 2) + pow(abs(plr->tileRect.y - ent->tileRect.y), 2)) < ENEMY_RANGE) { + plr->health -= ENEMY_DAMAGE; + } + if (plr->tileRect.x) + for (int y = ent->tileRect.y - ENEMY_RANGE; y < ent->tileRect.y + ENEMY_RANGE; y++) { + if (y < 0 || y >= MAP_HEIGHT) { + continue; + } + for (int x = ent->tileRect.x - ENEMY_RANGE; x < ent->tileRect.x + ENEMY_RANGE; x++) { + if (x < 0 || x >= MAP_WIDTH) { + continue; + } + Tile *targTile = &tileMap[y][x]; + if (targTile->type == TYPE_AIR) { + continue; + } + targTile->health -= ENEMY_DAMAGE; + if (targTile->health <= 0) { + if (targTile->audioCh < NUM_SYNTH_VOICES) { + audioData.synthVoices[targTile->audioCh].volume = 0; + } + memset(targTile->items, 0, sizeof(targTile->items)); + targTile->type = TYPE_AIR; + } + } + } + } + // Retry pathfinding every 10 ticks if we don't have a path and aren't at the target bool shouldRetryPathfinding = ( ent->path.length == 0 && @@ -93,9 +124,9 @@ void updateEntities() { .y = ent->toTile.y * TILE_SIZE }; - float t = (float)ent->interpolateTick / entT.entityTickRate; - ent->renderRect.x = (int)(from.x + (to.x - from.x) * t); - ent->renderRect.y = (int)(from.y + (to.y - from.y) * t); + float t = (float) ent->interpolateTick / entT.entityTickRate; + ent->renderRect.x = (int) (from.x + (to.x - from.x) * t); + ent->renderRect.y = (int) (from.y + (to.y - from.y) * t); if (ent->interpolateTick < entT.entityTickRate) { ent->interpolateTick++; @@ -104,9 +135,6 @@ void updateEntities() { } - - - void registerEntity(char fname[20], SDL_Renderer *renderer) { char name[21]; @@ -133,7 +161,6 @@ void registerEntity(char fname[20], SDL_Renderer *renderer) { //printf("Ent %s to %d\n", fname, indexEntity); - EntityRegistry[indexEntity].animation.textures[frame] = texture; EntityRegistry[indexEntity].animation.atlasRects[frame] = allocate_32x32(texture, renderer); EntityRegistry[indexEntity].type = indexEntity; diff --git a/entity/entity.h b/entity/entity.h index b99a4af..6fd28e1 100644 --- a/entity/entity.h +++ b/entity/entity.h @@ -7,9 +7,13 @@ #include "../tiles/tile.h" #include "../util/pathfinding.h" +#include "../player/player.h" #define ENTITY_MAX_COUNT 1024 +#define ENEMY_DAMAGE 2 +#define ENEMY_RANGE 3 + typedef enum EntityType { GHOST, } EntityType; @@ -49,7 +53,7 @@ void remove_entity(EntityArray *arr, int index); int add_entity(EntityArray *arr, Entity t); void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect); -void updateEntities(); +void updateEntities(Player * plr); void registerEntity(char fname[20], SDL_Renderer *renderer); void loadEntities(SDL_Renderer *renderer); diff --git a/items/item.c b/items/item.c index 868cf9a..931a82b 100644 --- a/items/item.c +++ b/items/item.c @@ -42,6 +42,72 @@ bool putOntoNext(ItemOnBelt *itm, int nx, int ny, Tile *next, TileTypeReg *ntt, } } + +OrientDirection rotateMainDirection(OrientDirection dir, int steps) { + + // The main directions indices array + int mainDirs[] = {1, 3, 5, 7}; + int count = 4; + + // Find index of dir in mainDirs + int index = 0; + for (; index < count; index++) { + if (mainDirs[index] == dir) break; + } + if (index == count) index = 0; // fallback + + // Rotate steps (positive = clockwise, negative = counterclockwise) + int newIndex = (index + steps) % count; + if (newIndex < 0) newIndex += count; + + return (OrientDirection)mainDirs[newIndex]; +} + +// Map 8 directions to main 4 for code output +int map8To4DirectionCode(OrientDirection dir) { + switch (dir) { + case ORIENT_LEFT: + return 4; // left + + case ORIENT_UP: + return 5; // up + + case ORIENT_RIGHT: + return 2; // right + + case ORIENT_DOWN: + return 3; // down + + default: + return 1; // undefined/error + } +} + +int getDirectionCode(OrientDirection dir, OrientDirection dir2) { + // Apply dir2 rotation: + switch (dir2) { + case ORIENT_UP: + // no change + break; + case ORIENT_LEFT: + // move dir one step to the right (clockwise) + dir = rotateMainDirection(dir, +1); + break; + case ORIENT_RIGHT: + // move dir one step to the left (counterclockwise) + dir = rotateMainDirection(dir, -1); + break; + case ORIENT_DOWN: + // move dir two steps to the left (counterclockwise) + dir = rotateMainDirection(dir, -2); + break; + default: + break; + } + return map8To4DirectionCode(dir); +} + + void updateItems() { for (int i = 0; i < neededUpdates.activeCount; i++) { @@ -70,52 +136,87 @@ void updateItems() { 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) { - if (tt.itemMoves) { - itm->offset += 1.0f - speed; - } - continue; + int inputDir = -1; // invalid by default + // Only valid if this tile is a belt and we can infer the input direction + if (tt.itemMoves) { + inputDir = (t->direction + 2) % 4; // Assume item entered from opposite of its direction } - Tile *next = &tileMap[ny][nx]; - TileTypeReg ntt = TileRegistry[next->type]; - int newLane = lane; - switch (next->type) { - case TYPE_BELT: - 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 ^ newDir == ORIENT_UP ? 0 : 1); - itm->offset = 0.0f; - } else if (vert && nH) { - // came off vertical: lane0=left→horizontal.top, lane1=right→horizontal.bottom - newLane = (dir == ORIENT_UP ^ newDir == ORIENT_RIGHT ? 1 : 0); - itm->offset = 0.0f; + bool handled = false; + if (tt.allDir) { + for (OrientDirection outDir = 0; outDir < ORIENT_DIRECTION_COUNT; outDir++) { + if (outDir == inputDir) continue; // skip input dir + + int nx = x + dirDx[outDir]; + int ny = y + dirDy[outDir]; + + if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) + continue; + + Tile *next = &tileMap[ny][nx]; + TileTypeReg ntt = TileRegistry[next->type]; + + // Try to put item into any slot + for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) { + if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) { + handled = true; + break; + } } - // (diagonals fall back to same-lane) - - // Find a free slot in - break; - - default: - itm->offset += 1.0f - speed; - } - - - if (!putOntoNext(itm, nx, ny, next, &ntt, newLane) && next->type != TYPE_BELT) { - for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) { - if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) { + if (handled) { + t->fixedFrame = getDirectionCode(outDir, t->direction); break; + }; + } + } else { + // 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) { + if (tt.itemMoves) { + itm->offset += 1.0f - speed; } + continue; + } + Tile *next = &tileMap[ny][nx]; + TileTypeReg ntt = TileRegistry[next->type]; + int newLane = lane; + switch (next->type) { + case TYPE_BELT: + 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 ^ newDir == ORIENT_UP ? 0 : 1); + itm->offset = 0.0f; + } else if (vert && nH) { + // came off vertical: lane0=left→horizontal.top, lane1=right→horizontal.bottom + newLane = (dir == ORIENT_UP ^ newDir == ORIENT_RIGHT ? 1 : 0); + itm->offset = 0.0f; + } + // (diagonals fall back to same-lane) + + // Find a free slot in + break; + + default: + itm->offset += 1.0f - speed; + } + + + if (!putOntoNext(itm, nx, ny, next, &ntt, newLane) && (next->type != TYPE_BELT || newLane >= 2)) { + for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) { + if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) { + break; + } + } + } } } @@ -284,10 +385,15 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play SDL_RenderFillRect(renderer, &rectA); } //SDL_RenderCopyx(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &tileRect); + SDL_RenderCopy(renderer, atlasTexture, - &ItemRegistry[item.type].beltAnimation.atlasRects[ORIENT_LEFT][ - (animationStep / ItemRegistry[item.type].beltAnimation.divisor) % - ItemRegistry[item.type].beltAnimation.frameCount], + &ItemRegistry[item.type].beltAnimation.atlasRects[ORIENT_LEFT][( + (animationStep / + ItemRegistry[item.type].beltAnimation.divisor) % + ( + ItemRegistry[item.type].beltAnimation.frameCount - + ItemRegistry[item.type].beltAnimation.startFrame)) + + ItemRegistry[item.type].beltAnimation.startFrame], &rect); if (debugMode) { @@ -311,24 +417,30 @@ void loadItems(SDL_Renderer *renderer) { strcpy(item->name, tile.name); memcpy(&item->animation, &tile.animation, sizeof(tile.animation)); + SDL_Texture *texTmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, TILE_SIZE, + TILE_SIZE); for (int frame = 0; frame < item->animation.frameCount; frame++) { for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) { - SDL_SetTextureBlendMode(item->animation.textures[a][frame], SDL_BLENDMODE_BLEND); - item->beltAnimation.textures[a][frame] = ScaleTexture(renderer, tile.animation.textures[a][frame], - TILE_SIZE / 2, TILE_SIZE / 2); - item->beltAnimation.atlasRects[a][frame] = allocate_16x16(item->beltAnimation.textures[a][frame], + SDL_SetRenderTarget(renderer, texTmp); + SDL_RenderCopy(renderer, atlasTexture, &tile.animation.atlasRects[a][frame], NULL); + SDL_Texture *tex = ScaleTexture(renderer, texTmp, + TILE_SIZE / 2, TILE_SIZE / 2); + item->beltAnimation.atlasRects[a][frame] = allocate_16x16(tex, renderer); + SDL_DestroyTexture(tex); if (frame + 1 > item->beltAnimation.frameCount) { item->beltAnimation.frameCount = frame + 1; } - SDL_SetTextureBlendMode(item->beltAnimation.textures[a][frame], SDL_BLENDMODE_BLEND); } } + SDL_DestroyTexture(texTmp); item->type = itemRegistryIndex; item->isTile = true; - item->animation.divisor = 1; - item->beltAnimation.divisor = 1; + item->animation.divisor = tile.animation.divisor; + item->beltAnimation.divisor = tile.animation.divisor; + item->animation.startFrame = tile.animation.startFrame; + item->beltAnimation.startFrame = tile.animation.startFrame; itemRegistryIndex++; } @@ -384,8 +496,6 @@ void loadItems(SDL_Renderer *renderer) { SDL_Rect beltRect = allocate_16x16(beltTex, renderer); // Assign to all orientations for (int o = 0; o < ORIENT_DIRECTION_COUNT; o++) { - item->animation.textures[o][frame] = tex; - item->beltAnimation.textures[o][frame] = beltTex; item->animation.atlasRects[o][frame] = mainRect; item->beltAnimation.atlasRects[o][frame] = beltRect; if (frame + 1 > item->animation.frameCount) { diff --git a/items/item.h b/items/item.h index 39340aa..fbe3d09 100644 --- a/items/item.h +++ b/items/item.h @@ -20,6 +20,8 @@ typedef enum ItemType { TYPE_FURNACE, TYPE_MINER, TYPE_TURRET, + TYPE_SPLITTER, + TYPE_CORE, IRON_ORE = ITEMREGISTRY_SIZE / 2, SILVER_ORE, GOLD_ORE, @@ -28,7 +30,11 @@ typedef enum ItemType { SILVER_INGOT, GOLD_INGOT, PLATINUM_INGOT, - LOG + LOG, + IRON_BULLET, + SILVER_BULLET, + GOLD_BULLET, + PLATINUM_BULLET, } ItemType; diff --git a/main.c b/main.c index d353747..94f1a99 100644 --- a/main.c +++ b/main.c @@ -83,6 +83,7 @@ const int delayNeeded = 1000 / targetFPS; #define smallFont fonts[1] #define smallerFont fonts[2] #define smallestFont fonts[3] +#define reallySmallestFont fonts[4] char *autosaveName = "autosave.dat"; @@ -150,11 +151,12 @@ int init() { loadBackgroundTiles(mainRenderer); loadTiles(mainRenderer); + preSetupTiles(); loadItems(mainRenderer); loadEntities(mainRenderer); - setupTiles(); + // for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) { // if (strlen(ItemRegistry[i].name)) { // printf("%d -> %s\n", i, ItemRegistry[i].name); @@ -206,10 +208,11 @@ int init() { SDL_RenderSetViewport(mainRenderer, &viewport); SDL_SetRenderDrawBlendMode(mainRenderer, SDL_BLENDMODE_BLEND); - biggerFont = prepText(mainRenderer, 16, "assets/PublicPixel.ttf", 255, 255, 255, 255); - smallFont = prepText(mainRenderer, 12, "assets/PublicPixel.ttf", 255, 255, 255, 255); - smallerFont = prepText(mainRenderer, 8, "assets/PublicPixel.ttf", 255, 255, 255, 255); - smallestFont = prepText(mainRenderer, 4, "assets/PublicPixel.ttf", 255, 255, 255, 255); + biggerFont = prepText(mainRenderer, 32, "assets/PublicPixel.ttf"); + smallFont = prepText(mainRenderer, 16, "assets/PublicPixel.ttf"); + smallerFont = prepText(mainRenderer, 12, "assets/PublicPixel.ttf"); + smallestFont = prepText(mainRenderer, 8, "assets/PublicPixel.ttf"); + reallySmallestFont = prepText(mainRenderer, 4, "assets/PublicPixel.ttf"); SDL_RenderSetLogicalSize(mainRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); initPlayer(&player); @@ -250,6 +253,17 @@ int render() { } else { SDL_RenderCopy(mainRenderer, atlasTexture, &rect2, &rect2); + unsigned int ix = ATLAS_SIZE; + for (unsigned char i = 1; i < fontCount; i++) { + SDL_Rect tmpRectFont = fonts[i].atlasRect; + tmpRectFont.x += ix; + SDL_RenderCopy(mainRenderer, fonts[i].atlas, &fonts[i].atlasRect, &tmpRectFont); + ix += fonts[i].atlasRect.w; + } + SDL_Rect tmpRectFont = fonts[0].atlasRect; + tmpRectFont.x += ATLAS_SIZE; + tmpRectFont.y = fonts[1].atlasRect.h; + SDL_RenderCopy(mainRenderer, fonts[0].atlas, &fonts[0].atlasRect, &tmpRectFont); } @@ -546,6 +560,31 @@ void processKeyboardHeld() { setActivePlayerSlot(&player, 0); } } + if (keyboardState[SDL_SCANCODE_E]) { + if (player.cursor.targetTile->health < TileRegistry[player.cursor.targetTile->type].maxHealth) { + player.cursor.targetTile->health++; + } + for (int x = playerTileX - 2; x < playerTileX + 2; x++) { + if (x < 0) { + continue; + } + if (x >= MAP_WIDTH) { + continue; + } + for (int y = playerTileY - 2; y < playerTileY + 2; y++) { + if (y < 0) { + continue; + } + if (y >= MAP_HEIGHT) { + continue; + } + Tile *t = &tileMap[y][x]; + if (t->health < TileRegistry[t->type].maxHealth) { + t->health++; + } + } + } + } if (keyboardState[SDL_SCANCODE_F9]) { player.inventory.slotCounts[player.inventory.activeSlotIndex]++; } @@ -649,7 +688,7 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[]) } } updateItems(); - updateEntities(); + updateEntities(&player); updatePlayer(&player); updateTiles(); animationStep++; diff --git a/player/player.c b/player/player.c index a5c2ee5..8c8612b 100644 --- a/player/player.c +++ b/player/player.c @@ -30,8 +30,9 @@ 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; + if ((activeSlotIndex < tileTypeIndex || + (activeSlotIndex < itemRegistryIndex && activeSlotIndex >= ITEMREGISTRY_SIZE / 2)) && activeSlotIndex > 0) { + plr->inventory.activeSlotIndex = activeSlotIndex; } } @@ -149,15 +150,27 @@ void initPlayer(Player *plr) { } void updatePlayer(Player *plr) { - if (plr->health == plr->prevHealth && plr->healthIdle < neededHealthIdle) { - plr->healthIdle++; + 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++; + // Don’t reset healthIdle here — only reset if something changes externally } + plr->prevHealth = plr->health; + + if (plr->health <= 0) { + plr->rect.x = DISPLAY_WIDTH / 2; + plr->rect.y = DISPLAY_HEIGHT / 2; + } } + void renderPlayer(Player *plr) { SDL_Texture *originalTarget = SDL_GetRenderTarget(mainRenderer); @@ -176,26 +189,39 @@ void renderPlayer(Player *plr) { ItemType itemIndex = plr->inventory.activeSlotIndex; //SDL_Texture *itemTex; char itemStringCount[6]; - if ((itemIndex < tileTypeIndex || (itemIndex < itemRegistryIndex && itemIndex >= ITEMREGISTRY_SIZE / 2)) && itemIndex > 0) { + 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].animation.divisor) % ItemRegistry[itemIndex].animation.frameCount]; + 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].animation.divisor) % ItemRegistry[itemIndex].animation.frameCount]; + 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(itemTex, 128, 128, 255); -// -// SDL_SetTextureAlphaMod(itemTex, 192); -// } else { -// SDL_SetTextureColorMod(itemTex, 255, 255, 255); -// -// SDL_SetTextureAlphaMod(itemTex, 255); -// } + 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]; @@ -204,6 +230,9 @@ void renderPlayer(Player *plr) { 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); + } @@ -213,7 +242,7 @@ void renderPlayer(Player *plr) { 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 - 90, 200, 8, + renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 110, 200, 8, tempko, tempko2, breakingBarColor, 4); } @@ -229,17 +258,29 @@ void renderPlayer(Player *plr) { if (ItemRegistry[i].name[0] == 0x00) { continue; } - SDL_Rect itemAtlasRectd = ItemRegistry[i].animation.atlasRects[plr->cursor.direction][(animationStep / ItemRegistry[i].animation.divisor) % ItemRegistry[i].animation.frameCount]; + 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].animation.divisor) % ItemRegistry[i].animation.frameCount]; + 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(itemTex, 128, 128, 255); -// } + 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(itemTex, 255, 255, 255); + SDL_SetTextureColorMod(atlasTexture, 255, 255, 255); if (plr->inventory.activeSlotIndex == i) { SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16, diff --git a/tiles/belt.c b/tiles/belt.c index 1b09468..2fdb647 100644 --- a/tiles/belt.c +++ b/tiles/belt.c @@ -9,10 +9,15 @@ #include "../player/player.h" #include "../items/item.h" #include "../util/atlas.h" +#include "../util/font.h" void generateBeltFrames(SDL_Renderer *renderer) { - SDL_Texture *baseTexture = TileRegistry[TYPE_BELT].animation.textures[ORIENT_LEFT][0]; // Base belt tile + SDL_Texture *baseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, + TILE_SIZE, + TILE_SIZE); SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer); + SDL_SetRenderTarget(renderer, baseTexture); + SDL_RenderCopy(renderer, atlasTexture, &TileRegistry[TYPE_BELT].animation.atlasRects[ORIENT_LEFT][0], NULL); const int frameCount = TILE_SIZE; // 32 frames, 1px per frame = full seamless loop for (OrientDirection dir = ORIENT_LEFT_DOWN; dir < ORIENT_DIRECTION_COUNT; dir++) { @@ -79,7 +84,6 @@ void generateBeltFrames(SDL_Renderer *renderer) { SDL_RenderCopy(renderer, rotated, NULL, &dst1); SDL_RenderCopy(renderer, rotated, NULL, &dst2); - TileRegistry[TYPE_BELT].animation.textures[dir][f] = frame; TileRegistry[TYPE_BELT].animation.atlasRects[dir][f] = allocate_32x32(frame, renderer); } @@ -88,6 +92,7 @@ void generateBeltFrames(SDL_Renderer *renderer) { TileRegistry[TYPE_BELT].animation.divisor = 1; } + SDL_DestroyTexture(baseTexture); SDL_SetRenderTarget(renderer, oldTarget); } @@ -103,4 +108,9 @@ void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect player (animationStep / TileRegistry[TYPE_BELT].animation.divisor) % TileRegistry[TYPE_BELT].animation.frameCount], &dst); + if (tileMap[y][x].health < TileRegistry[TYPE_BELT].maxHealth) { + char healthStr[12]; + snprintf(healthStr, 12, "%d/%d", tileMap[y][x].health, TileRegistry[tileMap[y][x].type].maxHealth); + renderText(renderer, fonts[3], healthStr, dst.x, dst.y); + } } \ No newline at end of file diff --git a/tiles/furnace.c b/tiles/furnace.c index 8cf38ac..f92b443 100644 --- a/tiles/furnace.c +++ b/tiles/furnace.c @@ -6,58 +6,20 @@ #include "tile.h" #include "../util/audio.h" -const ItemType FurnaceRecipes[ITEMREGISTRY_SIZE] = { - [IRON_ORE] = IRON_INGOT, - [SILVER_ORE] = SILVER_INGOT, - [GOLD_ORE] = GOLD_INGOT, - [PLATINUM_ORE] = PLATINUM_INGOT + +const MachineRecipe FurnaceRecipes[] = { + {IRON_ORE, TYPE_AIR, IRON_INGOT, 60}, + {SILVER_ORE, TYPE_AIR, SILVER_INGOT, 70}, + {GOLD_ORE, TYPE_AIR, GOLD_INGOT, 80}, + {PLATINUM_ORE, TYPE_AIR, PLATINUM_INGOT, 90} }; +void initFurnaceTile() { + initMachineTile(TYPE_FURNACE, FurnaceRecipes, sizeof(FurnaceRecipes) / sizeof(FurnaceRecipes[0]), + 1, /* start frame */ + 8 /* frame divisor */); +} void updateFurnace(Tile *tile) { - ItemOnBelt *inItem = &tile->items[FURNACE_INPUT_SLOT]; - ItemOnBelt *outItem = &tile->items[FURNACE_OUTPUT_SLOT]; - Item inItemType = ItemRegistry[inItem->type]; - - ItemType targetOutItemType = FurnaceRecipes[inItem->type]; - - Item targetOutItem = ItemRegistry[targetOutItemType]; - - if (targetOutItemType != TYPE_AIR) { - if (tile->miscVal == 0) { - if (outItem->type != TYPE_AIR) { - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 0; - } - tile->fixedFrame = 1; - return; - } - tile->audioCh = getAvailableChannel(); - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 255; - audioData.synthVoices[tile->audioCh].phase = 0; - audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->rect.x; - audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->rect.y; - audioData.synthVoices[tile->audioCh].waveform = WAVE_SINE; - audioData.synthVoices[tile->audioCh].frequency = 200; - } - tile->fixedFrame = 0; - } - ++audioData.synthVoices[tile->audioCh].frequency; - if (audioData.synthVoices[tile->audioCh].volume < 255) { - audioData.synthVoices[tile->audioCh].volume++; - } - if (outItem->type == 0 && ++tile->miscVal >= targetOutItem.miscVal) { - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 0; - } - tile->fixedFrame = 1; - tile->miscVal = 0; - inItem->type = 0; - outItem->type = targetOutItemType; - outItem->offset = -0.5f; - } - } else { - tile->fixedFrame = 1; - } + updateMachine(tile, FurnaceRecipes, sizeof(FurnaceRecipes) / sizeof(FurnaceRecipes[0]), WAVE_SINE, 200, 1); } \ No newline at end of file diff --git a/tiles/furnace.h b/tiles/furnace.h index 7f9f046..af975d6 100644 --- a/tiles/furnace.h +++ b/tiles/furnace.h @@ -7,8 +7,15 @@ #include "../items/item.h" #include "stdint.h" +#include "../util/crafter.h" -extern const ItemType FurnaceRecipes[]; +// Suppose this is defined somewhere +extern const MachineRecipe FurnaceRecipes[]; +extern const size_t FurnaceRecipeCount; + +void updateFurnace(Tile *tile); + +void initFurnaceTile(); #define FURNACE_INPUT_SLOT 0 #define FURNACE_OUTPUT_SLOT 1 diff --git a/tiles/miner.h b/tiles/miner.h index 7d01d44..9b446c1 100644 --- a/tiles/miner.h +++ b/tiles/miner.h @@ -8,8 +8,6 @@ #include "../items/item.h" #include "stdint.h" -extern const ItemType FurnaceRecipes[]; - #define MINER_OUTPUT_SLOT 0 void updateMiner(Tile * tile); diff --git a/tiles/tile.c b/tiles/tile.c index bd04607..11cb38a 100644 --- a/tiles/tile.c +++ b/tiles/tile.c @@ -113,7 +113,6 @@ void registerTile(char fname[20], SDL_Renderer *renderer) { }; // printf("Bound %s to %d orient %s\n", fname, indexTile, OrientStrings[o]); - TileRegistry[indexTile].animation.textures[o][frame] = textures[o]; SDL_SetTextureBlendMode(textures[o], SDL_BLENDMODE_BLEND); TileRegistry[indexTile].animation.atlasRects[o][frame] = allocate_32x32(textures[o], renderer); } @@ -126,6 +125,10 @@ void registerTile(char fname[20], SDL_Renderer *renderer) { 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; @@ -159,7 +162,6 @@ void registerBackgroundTile(char fname[20], SDL_Renderer *renderer) { //printf("Bound %s to %d\n", fname, indexBgTile); - BackgroundTileRegistry[indexBgTile].animation.textures[frame] = texture; BackgroundTileRegistry[indexBgTile].animation.atlasRects[frame] = allocate_32x32(texture, renderer); BackgroundTileRegistry[indexBgTile].type = indexBgTile; @@ -257,6 +259,17 @@ void loadBackgroundTiles(SDL_Renderer *renderer) { } } +void preSetupTiles() { + TileRegistry[TYPE_MINER].animation.startFrame = 1; + TileRegistry[TYPE_FURNACE].animation.divisor = 8; + TileRegistry[TYPE_CORE].animation.divisor = 8; + BackgroundTileRegistry[BGType_WATER_DEEP].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; @@ -268,33 +281,34 @@ void setupTiles() { TileRegistry[TYPE_BELT].allowedInItems[l][i] = true; } } - for (ItemType i = 0; i < itemRegistryIndex; i++) { - if (FurnaceRecipes[i] != 0) { - TileRegistry[TYPE_FURNACE].allowedInItems[FURNACE_INPUT_SLOT][i] = true; - } + TileRegistry[TYPE_SPLITTER].allowedInItems[0][i] = true; } -; TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1; - TileRegistry[TYPE_FURNACE].startFrame = 1; + 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_FURNACE].animation.divisor = 8; 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_MINER].startFrame = 1; TileRegistry[TYPE_AIR].walkable = true; TileRegistry[TYPE_TURRET].needsTicks = true; - TileRegistry[TYPE_TURRET].allowedInItems[TURRET_AMMO_INPUT_SLOT][IRON_INGOT] = 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_DEEP].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; BackgroundTileRegistry[BGType_WATER_SHALLOW].walkable = false; BackgroundTileRegistry[BGType_WATER_DEEP].walkable = false; + + initFurnaceTile(); } uint16_t getBreakTime(int type) { @@ -358,8 +372,6 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { printf("Error on tile %d, %d\n", x, y); backgroundMap[y][x].type = BGType_PLATINUM_ORE; } else { - SDL_Texture *tex = BackgroundTileRegistry[bt.type].animation.textures[animationStep % - BackgroundTileRegistry[bt.type].animation.frameCount]; SDL_Rect atlRect = BackgroundTileRegistry[bt.type].animation.atlasRects[ (animationStep / BackgroundTileRegistry[bt.type].animation.divisor) % BackgroundTileRegistry[bt.type].animation.frameCount]; @@ -396,20 +408,23 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { default: { char animationFrame = ((animationStep / TileRegistry[t.type].animation.divisor) % (TileRegistry[t.type].animation.frameCount - - TileRegistry[t.type].startFrame)) + TileRegistry[t.type].startFrame; + 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]; - SDL_Texture *tex = TileRegistry[t.type].animation.textures[t.direction][animationFrame]; if (atlRect.w == 0 || atlRect.h == 0) { - tex = TileRegistry[t.type].animation.textures[ORIENT_LEFT][animationFrame]; atlRect = TileRegistry[t.type].animation.atlasRects[ORIENT_LEFT][ animationFrame]; } if (atlRect.w != 0 && atlRect.h != 0) { - //SDL_RenderCopy(renderer, tex, NULL, &dstRect); 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, @@ -439,7 +454,7 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { .h = TILE_SIZE }; adjustRect(&dstRect, playerRect); - renderText(renderer, fonts[3], locChar, dstRect.x, dstRect.y); + renderText(renderer, fonts[4], locChar, dstRect.x, dstRect.y); } if (t.type == TYPE_BELT || itemViewing) { for (uint8_t lane = 0; lane < ItemSlotCount; lane++) { diff --git a/tiles/tile.h b/tiles/tile.h index 7d3335a..216db0f 100644 --- a/tiles/tile.h +++ b/tiles/tile.h @@ -7,6 +7,7 @@ #include "../util/util.h" #include "../items/item.h" +#include "tilecallbacks.h" #define MAP_WIDTH 500 #define MAP_HEIGHT 500 @@ -83,6 +84,8 @@ typedef enum BackgroundType { #define MAX_BASE_NAMES 512 #define MAX_ANIMATION_FRAMES 32 +typedef void (*UpdateTileCallback)(struct Tile *tile); + typedef struct TileTypeReg { ItemType type; char name[20]; @@ -92,9 +95,10 @@ typedef struct TileTypeReg { bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE]; bool outputLane[ItemSlotCount]; bool needsTicks; - char startFrame; bool walkable; + bool allDir; uint16_t maxHealth; + UpdateTileCallback updateTileCallback; } TileTypeReg; bool isWalkable(MiniRect tileCoords); @@ -141,7 +145,7 @@ typedef struct Tile { int neededUpdateIndex; char fixedFrame; PathFindDat pathFind; - uint16_t health; + int16_t health; } Tile; @@ -151,6 +155,8 @@ extern BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH]; void setupTiles(); +void preSetupTiles(); + void generateTestMap(); void loadBackgroundTiles(SDL_Renderer *renderer); diff --git a/tiles/turret.c b/tiles/turret.c index efdc35e..7c84602 100644 --- a/tiles/turret.c +++ b/tiles/turret.c @@ -8,7 +8,14 @@ #include "../entity/entity.h" const uint16_t AmmoDamages[ITEMREGISTRY_SIZE] = { - [IRON_INGOT] = 1 + [IRON_INGOT] = 2, + [GOLD_INGOT] = 1, + [SILVER_INGOT] = 3, + [PLATINUM_INGOT] = 5, + [IRON_BULLET] = 20, + [GOLD_BULLET] = 10, + [SILVER_BULLET] = 30, + [PLATINUM_BULLET] = 50, }; void updateTurret(Tile *tile) { @@ -17,45 +24,77 @@ void updateTurret(Tile *tile) { uint16_t damage = AmmoDamages[inItem->type]; - if (damage > 0) { - bool foundEnt = false; + // Reduce cooldown (miscVal) if above 0 + if (tile->miscVal > 0) { + tile->miscVal--; + } - for (int i = 0; i < entities.activeCount; i++) { - Entity *ent = &entities.entities[i]; - int dx = abs(ent->renderRect.x - (tile->rect.x * TILE_SIZE)); - int dy = abs(ent->renderRect.y - (tile->rect.y * TILE_SIZE)); - int d = sqrt(pow(dx, 2) + pow(dy, 2)); - if (d <= (TILE_SIZE * 8)) { - ent->health -= damage; - inItem->type = 0; - tile->audioCh = getAvailableChannel(); - if (tile->audioCh < NUM_SYNTH_VOICES) { - audioData.synthVoices[tile->audioCh].volume = 255; - audioData.synthVoices[tile->audioCh].phase = 0; - audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->rect.x; - audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->rect.y; - audioData.synthVoices[tile->audioCh].waveform = WAVE_TRIANGLE; - audioData.synthVoices[tile->audioCh].frequency = 400; - } - tile->fixedFrame = 0; - foundEnt = true; - break; - } - } - if (!foundEnt) { - audioData.synthVoices[tile->audioCh].volume = 0; - tile->fixedFrame = 1; - } - - - } else { + // If there's no ammo or it's invalid, stop the sound and return + if (damage == 0) { if (tile->audioCh < NUM_SYNTH_VOICES) { audioData.synthVoices[tile->audioCh].volume = 0; } - tile->fixedFrame = 1; + if (animationStep % (TileRegistry[tile->type].animation.frameCount - 1) == 0) { + tile->fixedFrame = 1; + } return; } - if (audioData.synthVoices[tile->audioCh].frequency > 80) { - audioData.synthVoices[tile->audioCh].frequency--; + + // Search for a target entity + bool foundEnt = false; + for (int i = 0; i < entities.activeCount; i++) { + Entity *ent = &entities.entities[i]; + int dx = abs(ent->renderRect.x - (tile->rect.x * TILE_SIZE)); + int dy = abs(ent->renderRect.y - (tile->rect.y * TILE_SIZE)); + int d = sqrt(dx * dx + dy * dy); + + if (d <= (TILE_SIZE * 8)) { + foundEnt = true; + + if (tile->miscVal == 0) { + // Do damage and consume ammo + ent->health -= damage; + inItem->type = 0; + + // Get or reuse audio channel + if (tile->audioCh >= NUM_SYNTH_VOICES) { + tile->audioCh = getAvailableChannel(); + } + + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *voice = &audioData.synthVoices[tile->audioCh]; + voice->volume = 255; + voice->phase = 0; + voice->sourceRect.x = tile->rect.x * TILE_SIZE; + voice->sourceRect.y = tile->rect.y * TILE_SIZE; + voice->waveform = WAVE_TRIANGLE; + voice->frequency = 400; + } + + tile->fixedFrame = 0; + tile->miscVal = 20; // Cooldown (ticks) until next fire + } + + break; // Only shoot one entity + } } -} \ No newline at end of file + + // No entity found? Fade sound out + if (!foundEnt && tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *voice = &audioData.synthVoices[tile->audioCh]; + if (voice->volume > 0) { + voice->volume--; + } + if (animationStep % (TileRegistry[tile->type].animation.frameCount - 1) == 0) { + tile->fixedFrame = 1; + } + } + + // Lower frequency for pitch effect if it's still playing + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *voice = &audioData.synthVoices[tile->audioCh]; + if (voice->frequency > 80) { + voice->frequency--; + } + } +} diff --git a/util/crafter.c b/util/crafter.c new file mode 100644 index 0000000..5608e8b --- /dev/null +++ b/util/crafter.c @@ -0,0 +1,97 @@ +// +// Created by bruno on 10.6.2025. +// + +#include "crafter.h" +#include "audio.h" + + +void initMachineTile(ItemType type, const MachineRecipe *recipes, size_t count, uint8_t startFrame, uint8_t divisor) { + // Force slot assignments for allowed items based on recipes + for (size_t i = 0; i < count; i++) { + const MachineRecipe *r = &recipes[i]; + if (r->input1 != TYPE_AIR) + TileRegistry[type].allowedInItems[SLOT_INPUT1][r->input1] = true; + if (r->input2 != TYPE_AIR) + TileRegistry[type].allowedInItems[SLOT_INPUT2][r->input2] = true; + } + + // Output slot is fixed to SLOT_OUTPUT + TileRegistry[type].outputLane[SLOT_OUTPUT] = 1; + + // Animation and behavior settings + TileRegistry[type].animation.startFrame = startFrame; + TileRegistry[type].animation.divisor = divisor; + TileRegistry[type].needsTicks = true; +} + + +bool findMachineRecipe(const MachineRecipe *recipes, size_t count, ItemType in1, ItemType in2, + ItemType *out, uint16_t *ticks) { + for (size_t i = 0; i < count; i++) { + const MachineRecipe *r = &recipes[i]; + if (r->input1 == in1 && r->input2 == in2) { + *out = r->output; + *ticks = r->ticksRequired; + return true; + } + } + return false; +} + +void updateMachine(Tile *tile, + const MachineRecipe *recipes, size_t recipeCount, + uint8_t waveform, uint16_t freqStart, uint16_t freqStep) { + ItemOnBelt *in1 = &tile->items[SLOT_INPUT1]; + ItemOnBelt *in2 = &tile->items[SLOT_INPUT2]; + ItemOnBelt *out = &tile->items[SLOT_OUTPUT]; + + ItemType result; + uint16_t ticksNeeded; + + if (!findMachineRecipe(recipes, recipeCount, in1->type, in2->type, &result, &ticksNeeded)) { + tile->fixedFrame = 1; + return; + } + + if (tile->miscVal == 0) { + if (out->type != TYPE_AIR) { + if (tile->audioCh < NUM_SYNTH_VOICES) + audioData.synthVoices[tile->audioCh].volume = 0; + tile->fixedFrame = 1; + return; + } + + tile->audioCh = getAvailableChannel(); + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *v = &audioData.synthVoices[tile->audioCh]; + v->volume = 255; + v->phase = 0; + v->waveform = waveform; + v->frequency = freqStart; + v->sourceRect.x = TILE_SIZE * tile->rect.x; + v->sourceRect.y = TILE_SIZE * tile->rect.y; + } + + tile->fixedFrame = 0; + } + + if (tile->audioCh < NUM_SYNTH_VOICES) { + SynthVoice *v = &audioData.synthVoices[tile->audioCh]; + v->frequency += freqStep; + } + + if (++tile->miscVal >= ticksNeeded) { + if (tile->audioCh < NUM_SYNTH_VOICES) + audioData.synthVoices[tile->audioCh].volume = 0; + + tile->miscVal = 0; + tile->fixedFrame = 1; + in1->type = TYPE_AIR; + if (in2->type != TYPE_AIR) in2->type = TYPE_AIR; + out->type = result; + out->tileX = tile->rect.x; + out->tileY = tile->rect.y; + out->offset = -0.5f; + } +} diff --git a/util/crafter.h b/util/crafter.h new file mode 100644 index 0000000..b0fe001 --- /dev/null +++ b/util/crafter.h @@ -0,0 +1,37 @@ +// +// Created by bruno on 10.6.2025. +// + +#ifndef FACTORYGAME_CRAFTER_H +#define FACTORYGAME_CRAFTER_H + +#include "../items/item.h" + +#define MATCHES(a, b, x, y) ((a == x && b == y) || (a == y && b == x)) + + +enum { + SLOT_INPUT1 = 0, + SLOT_INPUT2 = 1, + SLOT_OUTPUT = 2, + MACHINE_SLOTS = 3 +}; + +typedef struct { + ItemType input1; + ItemType input2; // use TYPE_AIR if single-input + ItemType output; + uint16_t ticksRequired; // used for output delay +} MachineRecipe; + +void updateMachine(Tile *tile, + const MachineRecipe *recipes, size_t recipeCount, + uint8_t waveform, uint16_t freqStart, uint16_t freqStep); + +bool findMachineRecipe(const MachineRecipe *recipes, size_t count, ItemType in1, ItemType in2, + ItemType *out, uint16_t *ticks); + +void initMachineTile(ItemType type, const MachineRecipe *recipes, size_t count, + uint8_t startFrame, uint8_t divisor); + +#endif //FACTORYGAME_CRAFTER_H diff --git a/util/font.c b/util/font.c index 6bd844c..ab554ac 100644 --- a/util/font.c +++ b/util/font.c @@ -7,58 +7,78 @@ BitmapFont fonts[fontCount]; -BitmapFont -prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { +BitmapFont prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file) { TTF_Font *gFont = TTF_OpenFont(file, pxSize); BitmapFont out; out.size = pxSize; - out.color = (SDL_Color) {r, g, b, a}; - unsigned int i = 1; - do { - if (i == 173) { //specifically this char is 0 width (IDK why) - out.surface[i] = SDL_CreateRGBSurface(0, pxSize, pxSize, 32, 0, 0, 0, 0); + out.color = (SDL_Color) {255, 255, 255, 255}; + + const int glyphsPerRow = 16; + const int glyphsPerCol = 16; + const int atlasWidth = glyphsPerRow * (pxSize + 1); + const int atlasHeight = glyphsPerCol * (pxSize + 1); + + SDL_Surface *atlasSurface = SDL_CreateRGBSurface(0, atlasWidth, atlasHeight, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + out.atlasRect.x = 0; + out.atlasRect.y = 0; + out.atlasRect.w = atlasWidth; + out.atlasRect.h = atlasHeight; + SDL_FillRect(atlasSurface, NULL, SDL_MapRGBA(atlasSurface->format, 0, 0, 0, 0)); // transparent + + for (uint16_t i = 1; i < 256; i++) { + SDL_Surface *surf; + + if (i == 173) { + surf = SDL_CreateRGBSurface(0, pxSize, pxSize, 32, + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + SDL_FillRect(surf, NULL, SDL_MapRGBA(surf->format, 0, 0, 0, 0)); // transparent } else { char tmpOut[2] = {i, 0}; - out.surface[i] = TTF_RenderText_Solid(gFont, tmpOut, out.color); + surf = TTF_RenderText_Solid(gFont, tmpOut, out.color); } - out.texture[i] = SDL_CreateTextureFromSurface(renderer, out.surface[i]); - i++; - } while (i < 256); + int x = (i % glyphsPerRow) * (pxSize + 1); + int y = (i / glyphsPerRow) * (pxSize + 1); + + SDL_Rect dest = {x, y, pxSize, pxSize}; + SDL_BlitSurface(surf, NULL, atlasSurface, &dest); + + out.glyphs[i] = dest; + + SDL_FreeSurface(surf); + } + + out.atlas = SDL_CreateTextureFromSurface(renderer, atlasSurface); + SDL_SetTextureBlendMode(out.atlas, SDL_BLENDMODE_BLEND); + SDL_FreeSurface(atlasSurface); TTF_CloseFont(gFont); + return out; } void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t x, uint16_t y) { - SDL_Rect charRect; - charRect.x = 0; - charRect.y = 0; - charRect.w = font.size; - charRect.h = font.size; - SDL_Rect outRect = charRect; + SDL_Rect outRect; outRect.x = x; outRect.y = y; + outRect.w = font.size; + outRect.h = font.size; while (*string) { if (*string == '\n') { outRect.x = x; - outRect.y += charRect.h + 4; + outRect.y += outRect.h + 4; string++; continue; } - SDL_RenderCopy(renderer, font.texture[*string], &charRect, &outRect); //TODO CONSIDER FONTS IN ONE ATLAS - outRect.x += charRect.w + 1; + SDL_RenderCopy(renderer, font.atlas, &font.glyphs[*string], &outRect); //TODO CONSIDER FONTS IN ONE ATLAS + outRect.x += outRect.w + 1; string++; } } void destroyFont(BitmapFont *font) { for (uint16_t i = 1; i < 256; i++) { - if (font->texture[i]) { - SDL_DestroyTexture(font->texture[i]); - } - if (font->surface[i]) { - SDL_FreeSurface(font->surface[i]); - } + SDL_DestroyTexture(font->atlas); } } \ No newline at end of file diff --git a/util/font.h b/util/font.h index 3430e9b..6302ae6 100644 --- a/util/font.h +++ b/util/font.h @@ -9,19 +9,20 @@ #include #include -#define fontCount 4 +#define fontCount 5 -typedef struct BitmapFont { - SDL_Texture *texture[256]; - SDL_Surface *surface[256]; +typedef struct { + SDL_Texture *atlas; + SDL_Rect glyphs[256]; uint8_t size; + SDL_Rect atlasRect; SDL_Color color; } BitmapFont; + extern BitmapFont fonts[fontCount]; -BitmapFont -prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +BitmapFont prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file); void destroyFont(BitmapFont *font); diff --git a/util/util.c b/util/util.c index 2d48927..cfd1b71 100644 --- a/util/util.c +++ b/util/util.c @@ -134,7 +134,7 @@ void renderBar(SDL_Renderer *renderer, char barString[20]; sprintf(barString, "%d/%d", currentValue, maxValue); - renderText(mainRenderer, fonts[3], barString, width / 2, margin); + renderText(mainRenderer, fonts[1], barString, x + (width / 2 - (fonts[2].size * strlen(barString))), y - fonts[2].size - barRect.h); } int cmpstringp(const void *p1, const void *p2) { diff --git a/util/util.h b/util/util.h index 2b7543e..483b566 100644 --- a/util/util.h +++ b/util/util.h @@ -38,7 +38,6 @@ extern bool itemViewing; extern bool renderAtlas; typedef struct Animation { - SDL_Texture *textures[TILE_SIZE]; SDL_Rect atlasRects[TILE_SIZE]; unsigned char frameCount; unsigned char divisor; @@ -46,10 +45,10 @@ typedef struct Animation { typedef struct OrientedAnimation { - SDL_Texture *textures[ORIENT_DIRECTION_COUNT][TILE_SIZE * 2]; SDL_Rect atlasRects[ORIENT_DIRECTION_COUNT][TILE_SIZE * 2]; unsigned char frameCount; unsigned char divisor; + char startFrame; } OrientedAnimation;