Most texure work
@@ -51,6 +51,8 @@ set(SOURCE_FILES
|
|||||||
entity/entity.h
|
entity/entity.h
|
||||||
tiles/turret.c
|
tiles/turret.c
|
||||||
tiles/turret.h
|
tiles/turret.h
|
||||||
|
util/crafter.c
|
||||||
|
util/crafter.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(factorygame ${SOURCE_FILES})
|
add_executable(factorygame ${SOURCE_FILES})
|
||||||
|
BIN
assets/items/08-iron_bullet-00.png
Normal file
After Width: | Height: | Size: 614 B |
BIN
assets/items/10-gold_bullet-00.png
Normal file
After Width: | Height: | Size: 464 B |
BIN
assets/items/11-platinum_bullet-00.png
Normal file
After Width: | Height: | Size: 662 B |
Before Width: | Height: | Size: 592 B After Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 489 B After Width: | Height: | Size: 528 B |
Before Width: | Height: | Size: 492 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 486 B After Width: | Height: | Size: 530 B |
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 539 B |
Before Width: | Height: | Size: 485 B After Width: | Height: | Size: 574 B |
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 565 B |
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 586 B |
Before Width: | Height: | Size: 481 B After Width: | Height: | Size: 583 B |
BIN
assets/tiles/04_miner_08.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
assets/tiles/04_miner_09.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
assets/tiles/04_miner_10.png
Normal file
After Width: | Height: | Size: 572 B |
Before Width: | Height: | Size: 239 B After Width: | Height: | Size: 393 B |
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 256 B After Width: | Height: | Size: 417 B |
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 415 B |
BIN
assets/tiles/05_turret_05.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
assets/tiles/05_turret_06.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
assets/tiles/05_turret_07.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
assets/tiles/05_turret_08.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
assets/tiles/05_turret_09.png
Normal file
After Width: | Height: | Size: 419 B |
BIN
assets/tiles/05_turret_10.png
Normal file
After Width: | Height: | Size: 390 B |
BIN
assets/tiles/05_turret_11.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
assets/tiles/05_turret_12.png
Normal file
After Width: | Height: | Size: 412 B |
BIN
assets/tiles/05_turret_13.png
Normal file
After Width: | Height: | Size: 410 B |
BIN
assets/tiles/05_turret_14.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
assets/tiles/05_turret_15.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
assets/tiles/05_turret_16.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
assets/tiles/05_turret_17.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
assets/tiles/05_turret_18.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
assets/tiles/05_turret_19.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
assets/tiles/05_turret_20.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
assets/tiles/05_turret_21.png
Normal file
After Width: | Height: | Size: 423 B |
BIN
assets/tiles/05_turret_22.png
Normal file
After Width: | Height: | Size: 420 B |
BIN
assets/tiles/05_turret_23.png
Normal file
After Width: | Height: | Size: 419 B |
BIN
assets/tiles/05_turret_24.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
assets/tiles/05_turret_25.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
assets/tiles/05_turret_26.png
Normal file
After Width: | Height: | Size: 428 B |
BIN
assets/tiles/05_turret_27.png
Normal file
After Width: | Height: | Size: 420 B |
BIN
assets/tiles/05_turret_28.png
Normal file
After Width: | Height: | Size: 410 B |
BIN
assets/tiles/05_turret_29.png
Normal file
After Width: | Height: | Size: 419 B |
BIN
assets/tiles/05_turret_30.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
assets/tiles/05_turret_31.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
assets/tiles/05_turret_32.png
Normal file
After Width: | Height: | Size: 416 B |
BIN
assets/tiles/05_turret_33.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
assets/tiles/05_turret_34.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
assets/tiles/05_turret_35.png
Normal file
After Width: | Height: | Size: 427 B |
BIN
assets/tiles/05_turret_36.png
Normal file
After Width: | Height: | Size: 408 B |
BIN
assets/tiles/05_turret_37.png
Normal file
After Width: | Height: | Size: 392 B |
BIN
assets/tiles/05_turret_38.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
assets/tiles/05_turret_39.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
assets/tiles/05_turret_40.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
assets/tiles/05_turret_41.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
assets/tiles/06_splitter_00.png
Normal file
After Width: | Height: | Size: 408 B |
BIN
assets/tiles/06_splitter_01.png
Normal file
After Width: | Height: | Size: 422 B |
BIN
assets/tiles/06_splitter_02.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
assets/tiles/06_splitter_03.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
assets/tiles/06_splitter_04.png
Normal file
After Width: | Height: | Size: 425 B |
BIN
assets/tiles/12_core_00.png
Normal file
After Width: | Height: | Size: 763 B |
BIN
assets/tiles/12_core_01.png
Normal file
After Width: | Height: | Size: 777 B |
BIN
assets/tiles/12_core_02.png
Normal file
After Width: | Height: | Size: 785 B |
BIN
assets/tiles/12_core_03.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
assets/tiles/12_core_04.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
assets/tiles/12_core_05.png
Normal file
After Width: | Height: | Size: 839 B |
BIN
assets/tiles/12_core_06.png
Normal file
After Width: | Height: | Size: 846 B |
BIN
assets/tiles/12_core_07.png
Normal file
After Width: | Height: | Size: 853 B |
BIN
assets/tiles/12_core_08.png
Normal file
After Width: | Height: | Size: 841 B |
BIN
assets/tiles/12_core_09.png
Normal file
After Width: | Height: | Size: 799 B |
BIN
assets/tiles/12_core_10.png
Normal file
After Width: | Height: | Size: 801 B |
BIN
assets/tiles/12_core_11.png
Normal file
After Width: | Height: | Size: 772 B |
BIN
assets/tiles/12_core_12.png
Normal file
After Width: | Height: | Size: 777 B |
BIN
assets/tiles/12_core_13.png
Normal file
After Width: | Height: | Size: 785 B |
BIN
assets/tiles/12_core_14.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
assets/tiles/12_core_15.png
Normal file
After Width: | Height: | Size: 839 B |
BIN
assets/tiles/12_core_16.png
Normal file
After Width: | Height: | Size: 846 B |
BIN
assets/tiles/12_core_17.png
Normal file
After Width: | Height: | Size: 853 B |
BIN
assets/tiles/12_core_18.png
Normal file
After Width: | Height: | Size: 799 B |
BIN
assets/tiles/12_core_19.png
Normal file
After Width: | Height: | Size: 801 B |
BIN
assets/tiles/12_core_20.png
Normal file
After Width: | Height: | Size: 772 B |
@@ -8,6 +8,7 @@
|
|||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../util/pathfinding.h"
|
#include "../util/pathfinding.h"
|
||||||
#include "../util/font.h"
|
#include "../util/font.h"
|
||||||
|
#include "../util/audio.h"
|
||||||
|
|
||||||
EntityArray entities;
|
EntityArray entities;
|
||||||
|
|
||||||
@@ -29,11 +30,12 @@ void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|||||||
SDL_RenderCopy(renderer, atlasTexture, &entType.animation.atlasRects[animationFrame], &renderRect);
|
SDL_RenderCopy(renderer, atlasTexture, &entType.animation.atlasRects[animationFrame], &renderRect);
|
||||||
char healthStr[12];
|
char healthStr[12];
|
||||||
snprintf(healthStr, 12, "%d/%d", ent->health, entType.maxHealth);
|
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);
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
}
|
}
|
||||||
void updateEntities() {
|
|
||||||
|
void updateEntities(Player *plr) {
|
||||||
for (int i = 0; i < entities.activeCount; i++) {
|
for (int i = 0; i < entities.activeCount; i++) {
|
||||||
Entity *ent = &entities.entities[i];
|
Entity *ent = &entities.entities[i];
|
||||||
EntityTypeReg entT = EntityRegistry[ent->type];
|
EntityTypeReg entT = EntityRegistry[ent->type];
|
||||||
@@ -48,6 +50,35 @@ void updateEntities() {
|
|||||||
bool atTarget = ent->tileRect.x == ent->target.x &&
|
bool atTarget = ent->tileRect.x == ent->target.x &&
|
||||||
ent->tileRect.y == ent->target.y;
|
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
|
// Retry pathfinding every 10 ticks if we don't have a path and aren't at the target
|
||||||
bool shouldRetryPathfinding = (
|
bool shouldRetryPathfinding = (
|
||||||
ent->path.length == 0 &&
|
ent->path.length == 0 &&
|
||||||
@@ -93,9 +124,9 @@ void updateEntities() {
|
|||||||
.y = ent->toTile.y * TILE_SIZE
|
.y = ent->toTile.y * TILE_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
float t = (float)ent->interpolateTick / entT.entityTickRate;
|
float t = (float) ent->interpolateTick / entT.entityTickRate;
|
||||||
ent->renderRect.x = (int)(from.x + (to.x - from.x) * t);
|
ent->renderRect.x = (int) (from.x + (to.x - from.x) * t);
|
||||||
ent->renderRect.y = (int)(from.y + (to.y - from.y) * t);
|
ent->renderRect.y = (int) (from.y + (to.y - from.y) * t);
|
||||||
|
|
||||||
if (ent->interpolateTick < entT.entityTickRate) {
|
if (ent->interpolateTick < entT.entityTickRate) {
|
||||||
ent->interpolateTick++;
|
ent->interpolateTick++;
|
||||||
@@ -104,9 +135,6 @@ void updateEntities() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void registerEntity(char fname[20], SDL_Renderer *renderer) {
|
void registerEntity(char fname[20], SDL_Renderer *renderer) {
|
||||||
char name[21];
|
char name[21];
|
||||||
|
|
||||||
@@ -133,7 +161,6 @@ void registerEntity(char fname[20], SDL_Renderer *renderer) {
|
|||||||
|
|
||||||
//printf("Ent %s to %d\n", fname, indexEntity);
|
//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].animation.atlasRects[frame] = allocate_32x32(texture, renderer);
|
||||||
|
|
||||||
EntityRegistry[indexEntity].type = indexEntity;
|
EntityRegistry[indexEntity].type = indexEntity;
|
||||||
|
@@ -7,9 +7,13 @@
|
|||||||
|
|
||||||
#include "../tiles/tile.h"
|
#include "../tiles/tile.h"
|
||||||
#include "../util/pathfinding.h"
|
#include "../util/pathfinding.h"
|
||||||
|
#include "../player/player.h"
|
||||||
|
|
||||||
#define ENTITY_MAX_COUNT 1024
|
#define ENTITY_MAX_COUNT 1024
|
||||||
|
|
||||||
|
#define ENEMY_DAMAGE 2
|
||||||
|
#define ENEMY_RANGE 3
|
||||||
|
|
||||||
typedef enum EntityType {
|
typedef enum EntityType {
|
||||||
GHOST,
|
GHOST,
|
||||||
} EntityType;
|
} EntityType;
|
||||||
@@ -49,7 +53,7 @@ void remove_entity(EntityArray *arr, int index);
|
|||||||
int add_entity(EntityArray *arr, Entity t);
|
int add_entity(EntityArray *arr, Entity t);
|
||||||
|
|
||||||
void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect);
|
void renderEntities(SDL_Renderer *renderer, SDL_Rect playerRect);
|
||||||
void updateEntities();
|
void updateEntities(Player * plr);
|
||||||
void registerEntity(char fname[20], SDL_Renderer *renderer);
|
void registerEntity(char fname[20], SDL_Renderer *renderer);
|
||||||
void loadEntities(SDL_Renderer *renderer);
|
void loadEntities(SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
134
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() {
|
void updateItems() {
|
||||||
|
|
||||||
for (int i = 0; i < neededUpdates.activeCount; i++) {
|
for (int i = 0; i < neededUpdates.activeCount; i++) {
|
||||||
@@ -70,6 +136,39 @@ void updateItems() {
|
|||||||
itm->offset -= 1.0f;
|
itm->offset -= 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (handled) {
|
||||||
|
t->fixedFrame = getDirectionCode(outDir, t->direction);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// target coords
|
// target coords
|
||||||
int nx = x + dirDx[dir];
|
int nx = x + dirDx[dir];
|
||||||
int ny = y + dirDy[dir];
|
int ny = y + dirDy[dir];
|
||||||
@@ -111,12 +210,14 @@ void updateItems() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!putOntoNext(itm, nx, ny, next, &ntt, newLane) && next->type != TYPE_BELT) {
|
if (!putOntoNext(itm, nx, ny, next, &ntt, newLane) && (next->type != TYPE_BELT || newLane >= 2)) {
|
||||||
for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) {
|
for (uint8_t nLane = 0; nLane < ItemSlotCount; nLane++) {
|
||||||
if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) {
|
if (putOntoNext(itm, nx, ny, next, &ntt, nLane)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,10 +385,15 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play
|
|||||||
SDL_RenderFillRect(renderer, &rectA);
|
SDL_RenderFillRect(renderer, &rectA);
|
||||||
}
|
}
|
||||||
//SDL_RenderCopyx(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &tileRect);
|
//SDL_RenderCopyx(renderer, ItemRegistry[item.type].textureOnBelt[ORIENT_LEFT], NULL, &tileRect);
|
||||||
|
|
||||||
SDL_RenderCopy(renderer, atlasTexture,
|
SDL_RenderCopy(renderer, atlasTexture,
|
||||||
&ItemRegistry[item.type].beltAnimation.atlasRects[ORIENT_LEFT][
|
&ItemRegistry[item.type].beltAnimation.atlasRects[ORIENT_LEFT][(
|
||||||
(animationStep / ItemRegistry[item.type].beltAnimation.divisor) %
|
(animationStep /
|
||||||
ItemRegistry[item.type].beltAnimation.frameCount],
|
ItemRegistry[item.type].beltAnimation.divisor) %
|
||||||
|
(
|
||||||
|
ItemRegistry[item.type].beltAnimation.frameCount -
|
||||||
|
ItemRegistry[item.type].beltAnimation.startFrame)) +
|
||||||
|
ItemRegistry[item.type].beltAnimation.startFrame],
|
||||||
&rect);
|
&rect);
|
||||||
|
|
||||||
if (debugMode) {
|
if (debugMode) {
|
||||||
@@ -311,24 +417,30 @@ void loadItems(SDL_Renderer *renderer) {
|
|||||||
strcpy(item->name, tile.name);
|
strcpy(item->name, tile.name);
|
||||||
memcpy(&item->animation, &tile.animation, sizeof(tile.animation));
|
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 frame = 0; frame < item->animation.frameCount; frame++) {
|
||||||
for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) {
|
for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) {
|
||||||
SDL_SetTextureBlendMode(item->animation.textures[a][frame], SDL_BLENDMODE_BLEND);
|
SDL_SetRenderTarget(renderer, texTmp);
|
||||||
item->beltAnimation.textures[a][frame] = ScaleTexture(renderer, tile.animation.textures[a][frame],
|
SDL_RenderCopy(renderer, atlasTexture, &tile.animation.atlasRects[a][frame], NULL);
|
||||||
|
SDL_Texture *tex = ScaleTexture(renderer, texTmp,
|
||||||
TILE_SIZE / 2, TILE_SIZE / 2);
|
TILE_SIZE / 2, TILE_SIZE / 2);
|
||||||
item->beltAnimation.atlasRects[a][frame] = allocate_16x16(item->beltAnimation.textures[a][frame],
|
item->beltAnimation.atlasRects[a][frame] = allocate_16x16(tex,
|
||||||
renderer);
|
renderer);
|
||||||
|
SDL_DestroyTexture(tex);
|
||||||
if (frame + 1 > item->beltAnimation.frameCount) {
|
if (frame + 1 > item->beltAnimation.frameCount) {
|
||||||
item->beltAnimation.frameCount = frame + 1;
|
item->beltAnimation.frameCount = frame + 1;
|
||||||
}
|
}
|
||||||
SDL_SetTextureBlendMode(item->beltAnimation.textures[a][frame], SDL_BLENDMODE_BLEND);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SDL_DestroyTexture(texTmp);
|
||||||
|
|
||||||
item->type = itemRegistryIndex;
|
item->type = itemRegistryIndex;
|
||||||
item->isTile = true;
|
item->isTile = true;
|
||||||
item->animation.divisor = 1;
|
item->animation.divisor = tile.animation.divisor;
|
||||||
item->beltAnimation.divisor = 1;
|
item->beltAnimation.divisor = tile.animation.divisor;
|
||||||
|
item->animation.startFrame = tile.animation.startFrame;
|
||||||
|
item->beltAnimation.startFrame = tile.animation.startFrame;
|
||||||
|
|
||||||
itemRegistryIndex++;
|
itemRegistryIndex++;
|
||||||
}
|
}
|
||||||
@@ -384,8 +496,6 @@ void loadItems(SDL_Renderer *renderer) {
|
|||||||
SDL_Rect beltRect = allocate_16x16(beltTex, renderer);
|
SDL_Rect beltRect = allocate_16x16(beltTex, renderer);
|
||||||
// Assign to all orientations
|
// Assign to all orientations
|
||||||
for (int o = 0; o < ORIENT_DIRECTION_COUNT; o++) {
|
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->animation.atlasRects[o][frame] = mainRect;
|
||||||
item->beltAnimation.atlasRects[o][frame] = beltRect;
|
item->beltAnimation.atlasRects[o][frame] = beltRect;
|
||||||
if (frame + 1 > item->animation.frameCount) {
|
if (frame + 1 > item->animation.frameCount) {
|
||||||
|
@@ -20,6 +20,8 @@ typedef enum ItemType {
|
|||||||
TYPE_FURNACE,
|
TYPE_FURNACE,
|
||||||
TYPE_MINER,
|
TYPE_MINER,
|
||||||
TYPE_TURRET,
|
TYPE_TURRET,
|
||||||
|
TYPE_SPLITTER,
|
||||||
|
TYPE_CORE,
|
||||||
IRON_ORE = ITEMREGISTRY_SIZE / 2,
|
IRON_ORE = ITEMREGISTRY_SIZE / 2,
|
||||||
SILVER_ORE,
|
SILVER_ORE,
|
||||||
GOLD_ORE,
|
GOLD_ORE,
|
||||||
@@ -28,7 +30,11 @@ typedef enum ItemType {
|
|||||||
SILVER_INGOT,
|
SILVER_INGOT,
|
||||||
GOLD_INGOT,
|
GOLD_INGOT,
|
||||||
PLATINUM_INGOT,
|
PLATINUM_INGOT,
|
||||||
LOG
|
LOG,
|
||||||
|
IRON_BULLET,
|
||||||
|
SILVER_BULLET,
|
||||||
|
GOLD_BULLET,
|
||||||
|
PLATINUM_BULLET,
|
||||||
} ItemType;
|
} ItemType;
|
||||||
|
|
||||||
|
|
||||||
|
51
main.c
@@ -83,6 +83,7 @@ const int delayNeeded = 1000 / targetFPS;
|
|||||||
#define smallFont fonts[1]
|
#define smallFont fonts[1]
|
||||||
#define smallerFont fonts[2]
|
#define smallerFont fonts[2]
|
||||||
#define smallestFont fonts[3]
|
#define smallestFont fonts[3]
|
||||||
|
#define reallySmallestFont fonts[4]
|
||||||
|
|
||||||
char *autosaveName = "autosave.dat";
|
char *autosaveName = "autosave.dat";
|
||||||
|
|
||||||
@@ -150,11 +151,12 @@ int init() {
|
|||||||
|
|
||||||
loadBackgroundTiles(mainRenderer);
|
loadBackgroundTiles(mainRenderer);
|
||||||
loadTiles(mainRenderer);
|
loadTiles(mainRenderer);
|
||||||
|
preSetupTiles();
|
||||||
loadItems(mainRenderer);
|
loadItems(mainRenderer);
|
||||||
loadEntities(mainRenderer);
|
loadEntities(mainRenderer);
|
||||||
|
|
||||||
setupTiles();
|
setupTiles();
|
||||||
|
|
||||||
|
|
||||||
// for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) {
|
// for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) {
|
||||||
// if (strlen(ItemRegistry[i].name)) {
|
// if (strlen(ItemRegistry[i].name)) {
|
||||||
// printf("%d -> %s\n", i, ItemRegistry[i].name);
|
// printf("%d -> %s\n", i, ItemRegistry[i].name);
|
||||||
@@ -206,10 +208,11 @@ int init() {
|
|||||||
SDL_RenderSetViewport(mainRenderer, &viewport);
|
SDL_RenderSetViewport(mainRenderer, &viewport);
|
||||||
|
|
||||||
SDL_SetRenderDrawBlendMode(mainRenderer, SDL_BLENDMODE_BLEND);
|
SDL_SetRenderDrawBlendMode(mainRenderer, SDL_BLENDMODE_BLEND);
|
||||||
biggerFont = prepText(mainRenderer, 16, "assets/PublicPixel.ttf", 255, 255, 255, 255);
|
biggerFont = prepText(mainRenderer, 32, "assets/PublicPixel.ttf");
|
||||||
smallFont = prepText(mainRenderer, 12, "assets/PublicPixel.ttf", 255, 255, 255, 255);
|
smallFont = prepText(mainRenderer, 16, "assets/PublicPixel.ttf");
|
||||||
smallerFont = prepText(mainRenderer, 8, "assets/PublicPixel.ttf", 255, 255, 255, 255);
|
smallerFont = prepText(mainRenderer, 12, "assets/PublicPixel.ttf");
|
||||||
smallestFont = prepText(mainRenderer, 4, "assets/PublicPixel.ttf", 255, 255, 255, 255);
|
smallestFont = prepText(mainRenderer, 8, "assets/PublicPixel.ttf");
|
||||||
|
reallySmallestFont = prepText(mainRenderer, 4, "assets/PublicPixel.ttf");
|
||||||
SDL_RenderSetLogicalSize(mainRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
SDL_RenderSetLogicalSize(mainRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
||||||
|
|
||||||
initPlayer(&player);
|
initPlayer(&player);
|
||||||
@@ -250,6 +253,17 @@ int render() {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
SDL_RenderCopy(mainRenderer, atlasTexture, &rect2, &rect2);
|
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);
|
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]) {
|
if (keyboardState[SDL_SCANCODE_F9]) {
|
||||||
player.inventory.slotCounts[player.inventory.activeSlotIndex]++;
|
player.inventory.slotCounts[player.inventory.activeSlotIndex]++;
|
||||||
}
|
}
|
||||||
@@ -649,7 +688,7 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateItems();
|
updateItems();
|
||||||
updateEntities();
|
updateEntities(&player);
|
||||||
updatePlayer(&player);
|
updatePlayer(&player);
|
||||||
updateTiles();
|
updateTiles();
|
||||||
animationStep++;
|
animationStep++;
|
||||||
|
@@ -30,7 +30,8 @@ SDL_Color breakingBarColor = {128, 128, 0, 255};
|
|||||||
|
|
||||||
void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) {
|
void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) {
|
||||||
activeSlotIndex = activeSlotIndex % itemRegistryIndex;
|
activeSlotIndex = activeSlotIndex % itemRegistryIndex;
|
||||||
if((activeSlotIndex < tileTypeIndex || (activeSlotIndex < itemRegistryIndex && activeSlotIndex >= ITEMREGISTRY_SIZE / 2)) && activeSlotIndex > 0) {
|
if ((activeSlotIndex < tileTypeIndex ||
|
||||||
|
(activeSlotIndex < itemRegistryIndex && activeSlotIndex >= ITEMREGISTRY_SIZE / 2)) && activeSlotIndex > 0) {
|
||||||
plr->inventory.activeSlotIndex = activeSlotIndex;
|
plr->inventory.activeSlotIndex = activeSlotIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,15 +150,27 @@ void initPlayer(Player *plr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updatePlayer(Player *plr) {
|
void updatePlayer(Player *plr) {
|
||||||
if (plr->health == plr->prevHealth && plr->healthIdle < neededHealthIdle) {
|
if (plr->health == plr->prevHealth) {
|
||||||
|
if (plr->healthIdle < neededHealthIdle)
|
||||||
plr->healthIdle++;
|
plr->healthIdle++;
|
||||||
|
} else {
|
||||||
|
plr->healthIdle = 0; // Reset if health changed (e.g., took damage or regen happened)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plr->health < playerMaxHealth && plr->healthIdle >= neededHealthIdle) {
|
if (plr->health < playerMaxHealth && plr->healthIdle >= neededHealthIdle) {
|
||||||
plr->health++;
|
plr->health++;
|
||||||
|
// Don’t reset healthIdle here — only reset if something changes externally
|
||||||
}
|
}
|
||||||
|
|
||||||
plr->prevHealth = plr->health;
|
plr->prevHealth = plr->health;
|
||||||
|
|
||||||
|
if (plr->health <= 0) {
|
||||||
|
plr->rect.x = DISPLAY_WIDTH / 2;
|
||||||
|
plr->rect.y = DISPLAY_HEIGHT / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void renderPlayer(Player *plr) {
|
void renderPlayer(Player *plr) {
|
||||||
|
|
||||||
SDL_Texture *originalTarget = SDL_GetRenderTarget(mainRenderer);
|
SDL_Texture *originalTarget = SDL_GetRenderTarget(mainRenderer);
|
||||||
@@ -176,26 +189,39 @@ void renderPlayer(Player *plr) {
|
|||||||
ItemType itemIndex = plr->inventory.activeSlotIndex;
|
ItemType itemIndex = plr->inventory.activeSlotIndex;
|
||||||
//SDL_Texture *itemTex;
|
//SDL_Texture *itemTex;
|
||||||
char itemStringCount[6];
|
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.x = plr->cursor.windowX;
|
||||||
plr->cursor.heldItemRect.y = plr->cursor.windowY;
|
plr->cursor.heldItemRect.y = plr->cursor.windowY;
|
||||||
//itemTex = ItemRegistry[itemIndex].textureOnBelt[plr->cursor.direction];
|
//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) {
|
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 (itemAtlasRect.w != 0 && itemAtlasRect.h != 0) {
|
||||||
|
|
||||||
// if (plr->inventory.slotCounts[itemIndex] <= 0) {
|
if (plr->inventory.slotCounts[itemIndex] <= 0) {
|
||||||
// // Set a red tint (255, 0, 0)
|
// Set a red tint (255, 0, 0)
|
||||||
// SDL_SetTextureColorMod(itemTex, 128, 128, 255);
|
SDL_SetTextureColorMod(atlasTexture, 128, 128, 255);
|
||||||
//
|
|
||||||
// SDL_SetTextureAlphaMod(itemTex, 192);
|
SDL_SetTextureAlphaMod(atlasTexture, 230);
|
||||||
// } else {
|
} else {
|
||||||
// SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
SDL_SetTextureColorMod(atlasTexture, 255, 255, 255);
|
||||||
//
|
|
||||||
// SDL_SetTextureAlphaMod(itemTex, 255);
|
SDL_SetTextureAlphaMod(atlasTexture, 255);
|
||||||
// }
|
}
|
||||||
// SDL_RenderCopy(mainRenderer, itemTex, NULL,
|
// SDL_RenderCopy(mainRenderer, itemTex, NULL,
|
||||||
// &plr->cursor.heldItemRect);
|
// &plr->cursor.heldItemRect);
|
||||||
char nameItem[80];
|
char nameItem[80];
|
||||||
@@ -204,6 +230,9 @@ void renderPlayer(Player *plr) {
|
|||||||
renderText(mainRenderer, fonts[2], nameItem, plr->cursor.heldItemRect.x,
|
renderText(mainRenderer, fonts[2], nameItem, plr->cursor.heldItemRect.x,
|
||||||
plr->cursor.heldItemRect.y - (fonts[2].size * 3 / 2));
|
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) {
|
if (plr->cursor.targetTile) {
|
||||||
uint16_t tempko = getBreakTime(plr->cursor.targetTile->type);
|
uint16_t tempko = getBreakTime(plr->cursor.targetTile->type);
|
||||||
uint16_t tempko2 = plr->cursor.breakingProgress;
|
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);
|
tempko, tempko2, breakingBarColor, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,17 +258,29 @@ void renderPlayer(Player *plr) {
|
|||||||
if (ItemRegistry[i].name[0] == 0x00) {
|
if (ItemRegistry[i].name[0] == 0x00) {
|
||||||
continue;
|
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) {
|
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 (itemAtlasRectd.w != 0 && itemAtlasRectd.h != 0) {
|
||||||
// if (plr->inventory.slotCounts[i] <= 0) {
|
if (plr->inventory.slotCounts[i] <= 0) {
|
||||||
// // Set a red tint (255, 0, 0)
|
// Set a red tint (255, 0, 0)
|
||||||
// SDL_SetTextureColorMod(itemTex, 128, 128, 255);
|
SDL_SetTextureColorMod(atlasTexture, 128, 128, 255);
|
||||||
// }
|
}
|
||||||
SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRectd, &targetItemRect);
|
SDL_RenderCopy(mainRenderer, atlasTexture, &itemAtlasRectd, &targetItemRect);
|
||||||
//SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
SDL_SetTextureColorMod(atlasTexture, 255, 255, 255);
|
||||||
|
|
||||||
if (plr->inventory.activeSlotIndex == i) {
|
if (plr->inventory.activeSlotIndex == i) {
|
||||||
SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16,
|
SDL_SetRenderDrawColor(mainRenderer, 16, plr->inventory.slotCounts[i] > 0 ? 128 : 16,
|
||||||
|
14
tiles/belt.c
@@ -9,10 +9,15 @@
|
|||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
#include "../util/atlas.h"
|
#include "../util/atlas.h"
|
||||||
|
#include "../util/font.h"
|
||||||
|
|
||||||
void generateBeltFrames(SDL_Renderer *renderer) {
|
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_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
|
const int frameCount = TILE_SIZE; // 32 frames, 1px per frame = full seamless loop
|
||||||
|
|
||||||
for (OrientDirection dir = ORIENT_LEFT_DOWN; dir < ORIENT_DIRECTION_COUNT; dir++) {
|
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, &dst1);
|
||||||
SDL_RenderCopy(renderer, rotated, NULL, &dst2);
|
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);
|
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;
|
TileRegistry[TYPE_BELT].animation.divisor = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_DestroyTexture(baseTexture);
|
||||||
SDL_SetRenderTarget(renderer, oldTarget);
|
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) %
|
(animationStep / TileRegistry[TYPE_BELT].animation.divisor) %
|
||||||
TileRegistry[TYPE_BELT].animation.frameCount],
|
TileRegistry[TYPE_BELT].animation.frameCount],
|
||||||
&dst);
|
&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);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -6,58 +6,20 @@
|
|||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "../util/audio.h"
|
#include "../util/audio.h"
|
||||||
|
|
||||||
const ItemType FurnaceRecipes[ITEMREGISTRY_SIZE] = {
|
|
||||||
[IRON_ORE] = IRON_INGOT,
|
const MachineRecipe FurnaceRecipes[] = {
|
||||||
[SILVER_ORE] = SILVER_INGOT,
|
{IRON_ORE, TYPE_AIR, IRON_INGOT, 60},
|
||||||
[GOLD_ORE] = GOLD_INGOT,
|
{SILVER_ORE, TYPE_AIR, SILVER_INGOT, 70},
|
||||||
[PLATINUM_ORE] = PLATINUM_INGOT
|
{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) {
|
void updateFurnace(Tile *tile) {
|
||||||
ItemOnBelt *inItem = &tile->items[FURNACE_INPUT_SLOT];
|
updateMachine(tile, FurnaceRecipes, sizeof(FurnaceRecipes) / sizeof(FurnaceRecipes[0]), WAVE_SINE, 200, 1);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -7,8 +7,15 @@
|
|||||||
|
|
||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
#include "stdint.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_INPUT_SLOT 0
|
||||||
#define FURNACE_OUTPUT_SLOT 1
|
#define FURNACE_OUTPUT_SLOT 1
|
||||||
|
@@ -8,8 +8,6 @@
|
|||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
extern const ItemType FurnaceRecipes[];
|
|
||||||
|
|
||||||
#define MINER_OUTPUT_SLOT 0
|
#define MINER_OUTPUT_SLOT 0
|
||||||
|
|
||||||
void updateMiner(Tile * tile);
|
void updateMiner(Tile * tile);
|
||||||
|
61
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]);
|
// 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);
|
SDL_SetTextureBlendMode(textures[o], SDL_BLENDMODE_BLEND);
|
||||||
TileRegistry[indexTile].animation.atlasRects[o][frame] = allocate_32x32(textures[o], renderer);
|
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].type = tileTypeIndex;
|
||||||
TileRegistry[indexTile].breakTime = 15;
|
TileRegistry[indexTile].breakTime = 15;
|
||||||
|
TileRegistry[indexTile].itemMoves = false;
|
||||||
|
TileRegistry[indexTile].walkable = false;
|
||||||
|
TileRegistry[indexTile].needsTicks = false;
|
||||||
|
TileRegistry[indexTile].updateTileCallback = NULL;
|
||||||
|
|
||||||
if (indexTile + 1 > tileTypeIndex) {
|
if (indexTile + 1 > tileTypeIndex) {
|
||||||
tileTypeIndex = indexTile + 1;
|
tileTypeIndex = indexTile + 1;
|
||||||
@@ -159,7 +162,6 @@ void registerBackgroundTile(char fname[20], SDL_Renderer *renderer) {
|
|||||||
|
|
||||||
//printf("Bound %s to %d\n", fname, indexBgTile);
|
//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].animation.atlasRects[frame] = allocate_32x32(texture, renderer);
|
||||||
|
|
||||||
BackgroundTileRegistry[indexBgTile].type = indexBgTile;
|
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() {
|
void setupTiles() {
|
||||||
TileRegistry[TYPE_AIR].breakTime = 0;
|
TileRegistry[TYPE_AIR].breakTime = 0;
|
||||||
TileRegistry[TYPE_BELT].itemMoves = true;
|
TileRegistry[TYPE_BELT].itemMoves = true;
|
||||||
@@ -268,33 +281,34 @@ void setupTiles() {
|
|||||||
TileRegistry[TYPE_BELT].allowedInItems[l][i] = true;
|
TileRegistry[TYPE_BELT].allowedInItems[l][i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ItemType i = 0; i < itemRegistryIndex; i++) {
|
for (ItemType i = 0; i < itemRegistryIndex; i++) {
|
||||||
if (FurnaceRecipes[i] != 0) {
|
TileRegistry[TYPE_SPLITTER].allowedInItems[0][i] = true;
|
||||||
TileRegistry[TYPE_FURNACE].allowedInItems[FURNACE_INPUT_SLOT][i] = true;
|
|
||||||
}
|
}
|
||||||
}
|
TileRegistry[TYPE_SPLITTER].outputLane[0] = true;
|
||||||
; TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1;
|
TileRegistry[TYPE_SPLITTER].needsTicks = true;
|
||||||
TileRegistry[TYPE_FURNACE].startFrame = 1;
|
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].needsTicks = true;
|
||||||
TileRegistry[TYPE_FURNACE].animation.divisor = 8;
|
|
||||||
TileRegistry[TYPE_BELT].needsTicks = true;
|
TileRegistry[TYPE_BELT].needsTicks = true;
|
||||||
TileRegistry[TYPE_BELT].walkable = true;
|
TileRegistry[TYPE_BELT].walkable = true;
|
||||||
TileRegistry[TYPE_MINER].needsTicks = true;
|
TileRegistry[TYPE_MINER].needsTicks = true;
|
||||||
TileRegistry[TYPE_MINER].outputLane[MINER_OUTPUT_SLOT] = 1;
|
TileRegistry[TYPE_MINER].outputLane[MINER_OUTPUT_SLOT] = 1;
|
||||||
TileRegistry[TYPE_MINER].startFrame = 1;
|
|
||||||
TileRegistry[TYPE_AIR].walkable = true;
|
TileRegistry[TYPE_AIR].walkable = true;
|
||||||
|
|
||||||
TileRegistry[TYPE_TURRET].needsTicks = 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_SHALLOW].walkable = false;
|
||||||
BackgroundTileRegistry[BGType_WATER_DEEP].walkable = false;
|
BackgroundTileRegistry[BGType_WATER_DEEP].walkable = false;
|
||||||
|
|
||||||
|
initFurnaceTile();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getBreakTime(int type) {
|
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);
|
printf("Error on tile %d, %d\n", x, y);
|
||||||
backgroundMap[y][x].type = BGType_PLATINUM_ORE;
|
backgroundMap[y][x].type = BGType_PLATINUM_ORE;
|
||||||
} else {
|
} else {
|
||||||
SDL_Texture *tex = BackgroundTileRegistry[bt.type].animation.textures[animationStep %
|
|
||||||
BackgroundTileRegistry[bt.type].animation.frameCount];
|
|
||||||
SDL_Rect atlRect = BackgroundTileRegistry[bt.type].animation.atlasRects[
|
SDL_Rect atlRect = BackgroundTileRegistry[bt.type].animation.atlasRects[
|
||||||
(animationStep / BackgroundTileRegistry[bt.type].animation.divisor) %
|
(animationStep / BackgroundTileRegistry[bt.type].animation.divisor) %
|
||||||
BackgroundTileRegistry[bt.type].animation.frameCount];
|
BackgroundTileRegistry[bt.type].animation.frameCount];
|
||||||
@@ -396,20 +408,23 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|||||||
default: {
|
default: {
|
||||||
char animationFrame = ((animationStep / TileRegistry[t.type].animation.divisor) %
|
char animationFrame = ((animationStep / TileRegistry[t.type].animation.divisor) %
|
||||||
(TileRegistry[t.type].animation.frameCount -
|
(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) {
|
if (t.fixedFrame > 0) {
|
||||||
animationFrame = t.fixedFrame - 1;
|
animationFrame = t.fixedFrame - 1;
|
||||||
}
|
}
|
||||||
SDL_Rect atlRect = TileRegistry[t.type].animation.atlasRects[t.direction][animationFrame];
|
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) {
|
if (atlRect.w == 0 || atlRect.h == 0) {
|
||||||
tex = TileRegistry[t.type].animation.textures[ORIENT_LEFT][animationFrame];
|
|
||||||
atlRect = TileRegistry[t.type].animation.atlasRects[ORIENT_LEFT][
|
atlRect = TileRegistry[t.type].animation.atlasRects[ORIENT_LEFT][
|
||||||
animationFrame];
|
animationFrame];
|
||||||
}
|
}
|
||||||
if (atlRect.w != 0 && atlRect.h != 0) {
|
if (atlRect.w != 0 && atlRect.h != 0) {
|
||||||
//SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
|
||||||
SDL_RenderCopy(renderer, atlasTexture, &atlRect, &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) {
|
// 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};
|
// 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,
|
// 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
|
.h = TILE_SIZE
|
||||||
};
|
};
|
||||||
adjustRect(&dstRect, playerRect);
|
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) {
|
if (t.type == TYPE_BELT || itemViewing) {
|
||||||
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
||||||
|
10
tiles/tile.h
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
|
#include "tilecallbacks.h"
|
||||||
|
|
||||||
#define MAP_WIDTH 500
|
#define MAP_WIDTH 500
|
||||||
#define MAP_HEIGHT 500
|
#define MAP_HEIGHT 500
|
||||||
@@ -83,6 +84,8 @@ typedef enum BackgroundType {
|
|||||||
#define MAX_BASE_NAMES 512
|
#define MAX_BASE_NAMES 512
|
||||||
#define MAX_ANIMATION_FRAMES 32
|
#define MAX_ANIMATION_FRAMES 32
|
||||||
|
|
||||||
|
typedef void (*UpdateTileCallback)(struct Tile *tile);
|
||||||
|
|
||||||
typedef struct TileTypeReg {
|
typedef struct TileTypeReg {
|
||||||
ItemType type;
|
ItemType type;
|
||||||
char name[20];
|
char name[20];
|
||||||
@@ -92,9 +95,10 @@ typedef struct TileTypeReg {
|
|||||||
bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE];
|
bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE];
|
||||||
bool outputLane[ItemSlotCount];
|
bool outputLane[ItemSlotCount];
|
||||||
bool needsTicks;
|
bool needsTicks;
|
||||||
char startFrame;
|
|
||||||
bool walkable;
|
bool walkable;
|
||||||
|
bool allDir;
|
||||||
uint16_t maxHealth;
|
uint16_t maxHealth;
|
||||||
|
UpdateTileCallback updateTileCallback;
|
||||||
} TileTypeReg;
|
} TileTypeReg;
|
||||||
|
|
||||||
bool isWalkable(MiniRect tileCoords);
|
bool isWalkable(MiniRect tileCoords);
|
||||||
@@ -141,7 +145,7 @@ typedef struct Tile {
|
|||||||
int neededUpdateIndex;
|
int neededUpdateIndex;
|
||||||
char fixedFrame;
|
char fixedFrame;
|
||||||
PathFindDat pathFind;
|
PathFindDat pathFind;
|
||||||
uint16_t health;
|
int16_t health;
|
||||||
} Tile;
|
} Tile;
|
||||||
|
|
||||||
|
|
||||||
@@ -151,6 +155,8 @@ extern BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH];
|
|||||||
|
|
||||||
void setupTiles();
|
void setupTiles();
|
||||||
|
|
||||||
|
void preSetupTiles();
|
||||||
|
|
||||||
void generateTestMap();
|
void generateTestMap();
|
||||||
|
|
||||||
void loadBackgroundTiles(SDL_Renderer *renderer);
|
void loadBackgroundTiles(SDL_Renderer *renderer);
|
||||||
|
@@ -8,7 +8,14 @@
|
|||||||
#include "../entity/entity.h"
|
#include "../entity/entity.h"
|
||||||
|
|
||||||
const uint16_t AmmoDamages[ITEMREGISTRY_SIZE] = {
|
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) {
|
void updateTurret(Tile *tile) {
|
||||||
@@ -17,45 +24,77 @@ void updateTurret(Tile *tile) {
|
|||||||
|
|
||||||
uint16_t damage = AmmoDamages[inItem->type];
|
uint16_t damage = AmmoDamages[inItem->type];
|
||||||
|
|
||||||
if (damage > 0) {
|
// Reduce cooldown (miscVal) if above 0
|
||||||
bool foundEnt = false;
|
if (tile->miscVal > 0) {
|
||||||
|
tile->miscVal--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
if (animationStep % (TileRegistry[tile->type].animation.frameCount - 1) == 0) {
|
||||||
|
tile->fixedFrame = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for a target entity
|
||||||
|
bool foundEnt = false;
|
||||||
for (int i = 0; i < entities.activeCount; i++) {
|
for (int i = 0; i < entities.activeCount; i++) {
|
||||||
Entity *ent = &entities.entities[i];
|
Entity *ent = &entities.entities[i];
|
||||||
int dx = abs(ent->renderRect.x - (tile->rect.x * TILE_SIZE));
|
int dx = abs(ent->renderRect.x - (tile->rect.x * TILE_SIZE));
|
||||||
int dy = abs(ent->renderRect.y - (tile->rect.y * TILE_SIZE));
|
int dy = abs(ent->renderRect.y - (tile->rect.y * TILE_SIZE));
|
||||||
int d = sqrt(pow(dx, 2) + pow(dy, 2));
|
int d = sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
if (d <= (TILE_SIZE * 8)) {
|
if (d <= (TILE_SIZE * 8)) {
|
||||||
|
foundEnt = true;
|
||||||
|
|
||||||
|
if (tile->miscVal == 0) {
|
||||||
|
// Do damage and consume ammo
|
||||||
ent->health -= damage;
|
ent->health -= damage;
|
||||||
inItem->type = 0;
|
inItem->type = 0;
|
||||||
|
|
||||||
|
// Get or reuse audio channel
|
||||||
|
if (tile->audioCh >= NUM_SYNTH_VOICES) {
|
||||||
tile->audioCh = getAvailableChannel();
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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->fixedFrame = 0;
|
||||||
foundEnt = true;
|
tile->miscVal = 20; // Cooldown (ticks) until next fire
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
break; // Only shoot one entity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundEnt) {
|
|
||||||
audioData.synthVoices[tile->audioCh].volume = 0;
|
// 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;
|
tile->fixedFrame = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lower frequency for pitch effect if it's still playing
|
||||||
} else {
|
|
||||||
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
audioData.synthVoices[tile->audioCh].volume = 0;
|
SynthVoice *voice = &audioData.synthVoices[tile->audioCh];
|
||||||
|
if (voice->frequency > 80) {
|
||||||
|
voice->frequency--;
|
||||||
}
|
}
|
||||||
tile->fixedFrame = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (audioData.synthVoices[tile->audioCh].frequency > 80) {
|
|
||||||
audioData.synthVoices[tile->audioCh].frequency--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
97
util/crafter.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
37
util/crafter.h
Normal file
@@ -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
|
72
util/font.c
@@ -7,58 +7,78 @@
|
|||||||
BitmapFont fonts[fontCount];
|
BitmapFont fonts[fontCount];
|
||||||
|
|
||||||
|
|
||||||
BitmapFont
|
BitmapFont prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file) {
|
||||||
prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
|
||||||
TTF_Font *gFont = TTF_OpenFont(file, pxSize);
|
TTF_Font *gFont = TTF_OpenFont(file, pxSize);
|
||||||
BitmapFont out;
|
BitmapFont out;
|
||||||
out.size = pxSize;
|
out.size = pxSize;
|
||||||
out.color = (SDL_Color) {r, g, b, a};
|
out.color = (SDL_Color) {255, 255, 255, 255};
|
||||||
unsigned int i = 1;
|
|
||||||
do {
|
const int glyphsPerRow = 16;
|
||||||
if (i == 173) { //specifically this char is 0 width (IDK why)
|
const int glyphsPerCol = 16;
|
||||||
out.surface[i] = SDL_CreateRGBSurface(0, pxSize, pxSize, 32, 0, 0, 0, 0);
|
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 {
|
} else {
|
||||||
char tmpOut[2] = {i, 0};
|
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);
|
TTF_CloseFont(gFont);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t x, uint16_t y) {
|
void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t x, uint16_t y) {
|
||||||
SDL_Rect charRect;
|
SDL_Rect outRect;
|
||||||
charRect.x = 0;
|
|
||||||
charRect.y = 0;
|
|
||||||
charRect.w = font.size;
|
|
||||||
charRect.h = font.size;
|
|
||||||
SDL_Rect outRect = charRect;
|
|
||||||
outRect.x = x;
|
outRect.x = x;
|
||||||
outRect.y = y;
|
outRect.y = y;
|
||||||
|
outRect.w = font.size;
|
||||||
|
outRect.h = font.size;
|
||||||
|
|
||||||
while (*string) {
|
while (*string) {
|
||||||
if (*string == '\n') {
|
if (*string == '\n') {
|
||||||
outRect.x = x;
|
outRect.x = x;
|
||||||
outRect.y += charRect.h + 4;
|
outRect.y += outRect.h + 4;
|
||||||
string++;
|
string++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SDL_RenderCopy(renderer, font.texture[*string], &charRect, &outRect); //TODO CONSIDER FONTS IN ONE ATLAS
|
SDL_RenderCopy(renderer, font.atlas, &font.glyphs[*string], &outRect); //TODO CONSIDER FONTS IN ONE ATLAS
|
||||||
outRect.x += charRect.w + 1;
|
outRect.x += outRect.w + 1;
|
||||||
string++;
|
string++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyFont(BitmapFont *font) {
|
void destroyFont(BitmapFont *font) {
|
||||||
for (uint16_t i = 1; i < 256; i++) {
|
for (uint16_t i = 1; i < 256; i++) {
|
||||||
if (font->texture[i]) {
|
SDL_DestroyTexture(font->atlas);
|
||||||
SDL_DestroyTexture(font->texture[i]);
|
|
||||||
}
|
|
||||||
if (font->surface[i]) {
|
|
||||||
SDL_FreeSurface(font->surface[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|