Start atlas
@@ -9,6 +9,8 @@ pkg_check_modules(SDL2 REQUIRED sdl2)
|
|||||||
|
|
||||||
|
|
||||||
add_executable(factorygame
|
add_executable(factorygame
|
||||||
|
tiles/tile.c
|
||||||
|
tiles/tile.h
|
||||||
util/font.c
|
util/font.c
|
||||||
util/font.h
|
util/font.h
|
||||||
util/audio.c
|
util/audio.c
|
||||||
@@ -17,13 +19,20 @@ add_executable(factorygame
|
|||||||
util/util.h
|
util/util.h
|
||||||
items/item.c
|
items/item.c
|
||||||
items/item.h
|
items/item.h
|
||||||
tiles/tile.c
|
|
||||||
tiles/tile.h
|
|
||||||
tiles/belt.c
|
tiles/belt.c
|
||||||
tiles/belt.h
|
tiles/belt.h
|
||||||
|
tiles/furnace.c
|
||||||
|
tiles/furnace.h
|
||||||
player/player.c
|
player/player.c
|
||||||
player/player.h # Ensure the target is defined before linking
|
player/player.h # Ensure the target is defined before linking
|
||||||
main.c)
|
tiles/tilecallbacks.c
|
||||||
|
tiles/tilecallbacks.h
|
||||||
|
main.c
|
||||||
|
util/perlin.c
|
||||||
|
util/perlin.h
|
||||||
|
util/atlas.c
|
||||||
|
util/atlas.h
|
||||||
|
)
|
||||||
|
|
||||||
# Define the path to the assets folder
|
# Define the path to the assets folder
|
||||||
set(ASSETS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/assets")
|
set(ASSETS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/assets")
|
||||||
|
BIN
assets/backgrounds/00water.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/backgrounds/01water.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/backgrounds/02grass.png
Normal file
After Width: | Height: | Size: 849 B |
BIN
assets/backgrounds/03grass.png
Normal file
After Width: | Height: | Size: 863 B |
BIN
assets/backgrounds/04grass.png
Normal file
After Width: | Height: | Size: 854 B |
BIN
assets/backgrounds/05grass.png
Normal file
After Width: | Height: | Size: 855 B |
BIN
assets/backgrounds/06grass.png
Normal file
After Width: | Height: | Size: 860 B |
BIN
assets/backgrounds/07grass.png
Normal file
After Width: | Height: | Size: 855 B |
BIN
assets/backgrounds/08grass.png
Normal file
After Width: | Height: | Size: 858 B |
BIN
assets/backgrounds/09grass.png
Normal file
After Width: | Height: | Size: 859 B |
BIN
assets/backgrounds/10grass.png
Normal file
After Width: | Height: | Size: 878 B |
BIN
assets/backgrounds/11grass.png
Normal file
After Width: | Height: | Size: 869 B |
BIN
assets/backgrounds/12grass.png
Normal file
After Width: | Height: | Size: 868 B |
BIN
assets/backgrounds/13grass.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
assets/backgrounds/14sand.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/backgrounds/15sand.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/backgrounds/16sand.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/backgrounds/17sand.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/backgrounds/18sand.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/backgrounds/19sand.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/backgrounds/20sand.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/backgrounds/21sand.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/backgrounds/22tiles.png
Normal file
After Width: | Height: | Size: 802 B |
BIN
assets/backgrounds/23tiles.png
Normal file
After Width: | Height: | Size: 814 B |
BIN
assets/backgrounds/24tiles.png
Normal file
After Width: | Height: | Size: 734 B |
BIN
assets/backgrounds/25tiles.png
Normal file
After Width: | Height: | Size: 739 B |
BIN
assets/backgrounds/26cobble.png
Normal file
After Width: | Height: | Size: 873 B |
BIN
assets/backgrounds/27cobble.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/backgrounds/28cobble.png
Normal file
After Width: | Height: | Size: 990 B |
BIN
assets/backgrounds/29cobble.png
Normal file
After Width: | Height: | Size: 837 B |
BIN
assets/backgrounds/30resource.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/backgrounds/31resource.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/backgrounds/32resource.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/backgrounds/33resource.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 546 B |
Before Width: | Height: | Size: 566 B After Width: | Height: | Size: 566 B |
Before Width: | Height: | Size: 526 B After Width: | Height: | Size: 526 B |
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 492 B After Width: | Height: | Size: 492 B |
Before Width: | Height: | Size: 530 B After Width: | Height: | Size: 530 B |
BIN
assets/tiles/3furnace.png
Normal file
After Width: | Height: | Size: 557 B |
83
items/item.c
@@ -5,6 +5,9 @@
|
|||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../util/font.h"
|
#include "../util/font.h"
|
||||||
|
#include "../tiles/furnace.h"
|
||||||
|
#include "../tiles/tilecallbacks.h"
|
||||||
|
#include "../util/atlas.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
Item ItemRegistry[ITEMREGISTRY_SIZE];
|
Item ItemRegistry[ITEMREGISTRY_SIZE];
|
||||||
@@ -22,22 +25,27 @@ void updateItems() {
|
|||||||
for (int y = 0; y < MAP_HEIGHT; y++) {
|
for (int y = 0; y < MAP_HEIGHT; y++) {
|
||||||
for (int x = 0; x < MAP_WIDTH; x++) {
|
for (int x = 0; x < MAP_WIDTH; x++) {
|
||||||
Tile *t = &tileMap[y][x];
|
Tile *t = &tileMap[y][x];
|
||||||
if (t->type != TYPE_BELT) continue;
|
TileTypeReg tt = TileRegistry[t->type];
|
||||||
|
if (t->type == TYPE_AIR) continue;
|
||||||
int dir = t->direction;
|
int dir = t->direction;
|
||||||
|
|
||||||
bool horz = (dir == ORIENT_LEFT || dir == ORIENT_RIGHT);
|
bool horz = (dir == ORIENT_LEFT || dir == ORIENT_RIGHT);
|
||||||
bool vert = (dir == ORIENT_UP || dir == ORIENT_DOWN);
|
bool vert = (dir == ORIENT_UP || dir == ORIENT_DOWN);
|
||||||
|
|
||||||
for (uint8_t lane = 0; lane < 2; lane++) {
|
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
||||||
|
if (!tt.outputLane[lane]) continue;
|
||||||
ItemOnBelt *itm = &t->items[lane];
|
ItemOnBelt *itm = &t->items[lane];
|
||||||
if (itm->type == 0) continue;
|
if (itm->type == 0) continue;
|
||||||
|
if (tt.itemMoves) {
|
||||||
// 1) Advance
|
|
||||||
itm->offset += speed;
|
itm->offset += speed;
|
||||||
|
// 1) Advance
|
||||||
|
}
|
||||||
|
|
||||||
// 2) Time to hop?
|
// 2) Time to hop?
|
||||||
if (itm->offset >= 0.5f) {
|
if (itm->offset >= 0.5f || !tt.itemMoves) {
|
||||||
|
if (tt.itemMoves) {
|
||||||
itm->offset -= 1.0f;
|
itm->offset -= 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
// target coords
|
// target coords
|
||||||
int nx = x + dirDx[dir];
|
int nx = x + dirDx[dir];
|
||||||
@@ -45,19 +53,16 @@ void updateItems() {
|
|||||||
|
|
||||||
// bounds & belt?
|
// bounds & belt?
|
||||||
if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) {
|
if (nx < 0 || nx >= MAP_WIDTH || ny < 0 || ny >= MAP_HEIGHT) {
|
||||||
//itm->type = 0;
|
if (tt.itemMoves) {
|
||||||
itm->offset += 1.0f - speed;
|
itm->offset += 1.0f - speed;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Tile *next = &tileMap[ny][nx];
|
Tile *next = &tileMap[ny][nx];
|
||||||
if (next->type != TYPE_BELT) {
|
TileTypeReg ntt = TileRegistry[next->type];
|
||||||
//itm->type = 0;
|
|
||||||
itm->offset += 1.0f - speed;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decide new lane
|
|
||||||
int newLane = lane;
|
int newLane = lane;
|
||||||
|
switch (next->type) {
|
||||||
|
case TYPE_BELT:
|
||||||
int newDir = next->direction;
|
int newDir = next->direction;
|
||||||
bool nH = (newDir == ORIENT_LEFT || newDir == ORIENT_RIGHT);
|
bool nH = (newDir == ORIENT_LEFT || newDir == ORIENT_RIGHT);
|
||||||
bool nV = (newDir == ORIENT_UP || newDir == ORIENT_DOWN);
|
bool nV = (newDir == ORIENT_UP || newDir == ORIENT_DOWN);
|
||||||
@@ -76,12 +81,21 @@ void updateItems() {
|
|||||||
// (diagonals fall back to same-lane)
|
// (diagonals fall back to same-lane)
|
||||||
|
|
||||||
// Find a free slot in
|
// Find a free slot in
|
||||||
|
break;
|
||||||
|
|
||||||
if (next->items[newLane].type == 0) {
|
default:
|
||||||
|
itm->offset += 1.0f - speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (next->items[newLane].type == 0 && ntt.allowedInItems[newLane][itm->type]) {
|
||||||
// MOVE it
|
// MOVE it
|
||||||
ItemOnBelt moved = *itm;
|
ItemOnBelt moved = *itm;
|
||||||
moved.tileX = nx;
|
moved.tileX = nx;
|
||||||
moved.tileY = ny;
|
moved.tileY = ny;
|
||||||
|
if (!ntt.itemMoves) {
|
||||||
|
moved.offset = 0.5f;
|
||||||
|
}
|
||||||
next->items[newLane] = moved;
|
next->items[newLane] = moved;
|
||||||
|
|
||||||
// clear this one
|
// clear this one
|
||||||
@@ -90,8 +104,15 @@ void updateItems() {
|
|||||||
// both slots full → wait at end
|
// both slots full → wait at end
|
||||||
itm->offset = epsilon;
|
itm->offset = epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const UpdateTileCallback cb = ItemTileCallbacks[t->type];
|
||||||
|
if (cb) {
|
||||||
|
cb(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +129,11 @@ void registerItem(char name[20], SDL_Renderer *renderer) {
|
|||||||
ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT],
|
ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT],
|
||||||
TILE_SIZE / 2, TILE_SIZE / 2);
|
TILE_SIZE / 2, TILE_SIZE / 2);
|
||||||
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
||||||
|
ItemRegistry[itemRegistryIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(ItemRegistry[itemRegistryIndex].texture[ORIENT_LEFT], renderer);
|
||||||
|
ItemRegistry[itemRegistryIndex].atlasRectsOnBelt[ORIENT_LEFT] = allocate_16x16(ItemRegistry[itemRegistryIndex].textureOnBelt[ORIENT_LEFT], renderer);
|
||||||
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
|
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
|
||||||
|
ItemRegistry[itemRegistryIndex].isTile = false;
|
||||||
|
ItemRegistry[itemRegistryIndex].miscVal = 60;
|
||||||
|
|
||||||
itemRegistryIndex++;
|
itemRegistryIndex++;
|
||||||
}
|
}
|
||||||
@@ -196,7 +221,7 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play
|
|||||||
yOffset += 0.0f * TILE_SIZE;
|
yOffset += 0.0f * TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case ORIENT_LEFT:
|
case ORIENT_LEFT:
|
||||||
xOffset += 0.0f * TILE_SIZE + (TILE_SIZE / 2);
|
xOffset += 0.0f * TILE_SIZE + (TILE_SIZE);
|
||||||
yOffset += 0.26f * TILE_SIZE;
|
yOffset += 0.26f * TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case ORIENT_LEFT_UP:
|
case ORIENT_LEFT_UP:
|
||||||
@@ -205,14 +230,14 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play
|
|||||||
break;
|
break;
|
||||||
case ORIENT_UP:
|
case ORIENT_UP:
|
||||||
xOffset += 0.22f * TILE_SIZE; //GOTO HEHREHRHE
|
xOffset += 0.22f * TILE_SIZE; //GOTO HEHREHRHE
|
||||||
yOffset += 0.0f * TILE_SIZE + (TILE_SIZE / 2);
|
yOffset += 0.0f * TILE_SIZE + (TILE_SIZE);
|
||||||
break;
|
break;
|
||||||
case ORIENT_RIGHT_UP:
|
case ORIENT_RIGHT_UP:
|
||||||
xOffset += 0.0f * TILE_SIZE;
|
xOffset += 0.0f * TILE_SIZE;
|
||||||
yOffset += 0.0f * TILE_SIZE;
|
yOffset += 0.0f * TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case ORIENT_RIGHT:
|
case ORIENT_RIGHT:
|
||||||
xOffset += 0.0f * TILE_SIZE;
|
xOffset += 0.0f * TILE_SIZE - (TILE_SIZE / 2);
|
||||||
yOffset += 0.18f * TILE_SIZE; //FIX THIS
|
yOffset += 0.18f * TILE_SIZE; //FIX THIS
|
||||||
break;
|
break;
|
||||||
case ORIENT_RIGHT_DOWN:
|
case ORIENT_RIGHT_DOWN:
|
||||||
@@ -220,8 +245,8 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play
|
|||||||
yOffset += 0.0f * TILE_SIZE;
|
yOffset += 0.0f * TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case ORIENT_DOWN:
|
case ORIENT_DOWN:
|
||||||
xOffset += 0.18f * TILE_SIZE + (TILE_SIZE / 4);
|
xOffset += 0.18f * TILE_SIZE + (TILE_SIZE / 8);
|
||||||
yOffset += 0.0f * TILE_SIZE;
|
yOffset += 0.0f * TILE_SIZE - (TILE_SIZE / 2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -275,7 +300,7 @@ void renderItem(ItemOnBelt item, SDL_Renderer *renderer, int lane, SDL_Rect play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void putItem(int x, int y, uint16_t itemType, uint8_t lane) {
|
void putItem(int x, int y, ItemType itemType, uint8_t lane) {
|
||||||
tileMap[y][x].items[lane].type = itemType;
|
tileMap[y][x].items[lane].type = itemType;
|
||||||
tileMap[y][x].items[lane].offset = 0;
|
tileMap[y][x].items[lane].offset = 0;
|
||||||
tileMap[y][x].items[lane].tileX = x;
|
tileMap[y][x].items[lane].tileX = x;
|
||||||
@@ -283,33 +308,29 @@ void putItem(int x, int y, uint16_t itemType, uint8_t lane) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loadItems(SDL_Renderer *renderer) {
|
void loadItems(SDL_Renderer *renderer) {
|
||||||
|
|
||||||
for (int i = 0; i < tileTypeIndex; i++) {
|
for (int i = 0; i < tileTypeIndex; i++) {
|
||||||
TileType tile = TileRegistry[i];
|
TileTypeReg tile = TileRegistry[i];
|
||||||
|
|
||||||
strcpy(ItemRegistry[itemRegistryIndex].name, tile.name);
|
strcpy(ItemRegistry[itemRegistryIndex].name, tile.name);
|
||||||
memcpy(ItemRegistry[itemRegistryIndex].texture, tile.textures, sizeof(tile.textures));
|
memcpy(ItemRegistry[itemRegistryIndex].texture, tile.textures, sizeof(tile.textures));
|
||||||
|
memcpy(ItemRegistry[itemRegistryIndex].atlasRects, tile.atlasRects, sizeof(tile.atlasRects));
|
||||||
for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) {
|
for (int a = 0; a < ORIENT_DIRECTION_COUNT; a++) {
|
||||||
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].texture[a], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].texture[a], SDL_BLENDMODE_BLEND);
|
||||||
ItemRegistry[itemRegistryIndex].textureOnBelt[a] = ScaleTexture(renderer, tile.textures[a],
|
ItemRegistry[itemRegistryIndex].textureOnBelt[a] = ScaleTexture(renderer, tile.textures[a],
|
||||||
TILE_SIZE / 2, TILE_SIZE / 2);
|
TILE_SIZE / 2, TILE_SIZE / 2);
|
||||||
|
ItemRegistry[itemRegistryIndex].atlasRectsOnBelt[a] = allocate_16x16(
|
||||||
|
ItemRegistry[itemRegistryIndex].textureOnBelt[a], renderer);
|
||||||
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[a], SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt[a], SDL_BLENDMODE_BLEND);
|
||||||
}
|
}
|
||||||
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
|
ItemRegistry[itemRegistryIndex].type = itemRegistryIndex;
|
||||||
|
ItemRegistry[itemRegistryIndex].isTile = true;
|
||||||
|
|
||||||
itemRegistryIndex++;
|
itemRegistryIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
itemRegistryIndex = ITEMREGISTRY_SIZE / 2;
|
||||||
iterateSortedDir("./assets/items", (DirEntryCallback) registerItem, renderer);
|
iterateSortedDir("./assets/items", (DirEntryCallback) registerItem, renderer);
|
||||||
|
|
||||||
// DIR *dir = opendir("./assets/items");
|
|
||||||
// if (dir) {
|
|
||||||
// struct dirent *entry;
|
|
||||||
// while ((entry = readdir(dir)) != NULL) {
|
|
||||||
// if (entry->d_name[0] == '.') {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// registerItem(entry->d_name, mainRenderer);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
35
items/item.h
@@ -5,23 +5,46 @@
|
|||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
#include "../tiles/belt.h"
|
#include "../tiles/belt.h"
|
||||||
|
#include "../tiles/tile.h"
|
||||||
|
|
||||||
#ifndef FACTORYGAME_ITEM_H
|
#ifndef FACTORYGAME_ITEM_H
|
||||||
#define FACTORYGAME_ITEM_H
|
#define FACTORYGAME_ITEM_H
|
||||||
|
|
||||||
#define ITEMREGISTRY_SIZE 20
|
#define ITEMREGISTRY_SIZE 128
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
|
typedef enum ItemType {
|
||||||
|
TYPE_AIR = 0,
|
||||||
|
TYPE_BLOCK,
|
||||||
|
TYPE_BELT,
|
||||||
|
TYPE_FURNACE,
|
||||||
|
IRON_ORE = ITEMREGISTRY_SIZE / 2,
|
||||||
|
SILVER_ORE,
|
||||||
|
GOLD_ORE,
|
||||||
|
PLATINUM_ORE,
|
||||||
|
IRON_INGOT,
|
||||||
|
SILVER_INGOT,
|
||||||
|
GOLD_INGOT,
|
||||||
|
PLATINUM_INGOT,
|
||||||
|
LOG
|
||||||
|
} ItemType;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ItemOnBelt {
|
||||||
float offset;
|
float offset;
|
||||||
int tileX, tileY;
|
int tileX, tileY;
|
||||||
uint16_t type;
|
ItemType type;
|
||||||
} ItemOnBelt;
|
} ItemOnBelt;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Item {
|
||||||
uint16_t type;
|
bool isTile;
|
||||||
|
ItemType type;
|
||||||
char name[20];
|
char name[20];
|
||||||
|
uint16_t miscVal;
|
||||||
SDL_Texture * texture[ORIENT_DIRECTION_COUNT];
|
SDL_Texture * texture[ORIENT_DIRECTION_COUNT];
|
||||||
SDL_Texture * textureOnBelt[ORIENT_DIRECTION_COUNT];
|
SDL_Texture * textureOnBelt[ORIENT_DIRECTION_COUNT];
|
||||||
|
SDL_Rect atlasRects[ORIENT_DIRECTION_COUNT];
|
||||||
|
SDL_Rect atlasRectsOnBelt[ORIENT_DIRECTION_COUNT];
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
|
|
||||||
@@ -39,5 +62,5 @@ extern uint8_t laneTarget;
|
|||||||
extern double speed;
|
extern double speed;
|
||||||
|
|
||||||
|
|
||||||
void putItem(int x, int y, uint16_t itemType, uint8_t lane);
|
void putItem(int x, int y, ItemType itemType, uint8_t lane);
|
||||||
#endif //FACTORYGAME_ITEM_H
|
#endif //FACTORYGAME_ITEM_H
|
||||||
|
244
main.c
@@ -7,28 +7,46 @@
|
|||||||
#include "items/item.h"
|
#include "items/item.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "player/player.h"
|
#include "player/player.h"
|
||||||
|
#include "util/perlin.h"
|
||||||
|
#include "util/atlas.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct GameState {
|
||||||
Player player;
|
Player player;
|
||||||
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
|
BackgroundTile backgroundTileMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
|
SynthVoice voices[NUM_SYNTH_VOICES];
|
||||||
} GameState;
|
} GameState;
|
||||||
GameState gameState;
|
GameState gameState;
|
||||||
|
|
||||||
void loadGameState(char *filename, Player *plr) {
|
int loadGameState(char *filename, Player *plr) {
|
||||||
printf("hello from load\n");
|
printf("hello from load\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
FILE *gameSave = fopen(filename, "rb");
|
FILE *gameSave = fopen(filename, "rb");
|
||||||
if (gameSave) {
|
if (gameSave) {
|
||||||
|
fseek(gameSave, 0L, SEEK_END);
|
||||||
|
long sz = ftell(gameSave);
|
||||||
|
if (sz != sizeof(gameState)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
rewind(gameSave);
|
||||||
fread(&gameState, sizeof(gameState), 1, gameSave);
|
fread(&gameState, sizeof(gameState), 1, gameSave);
|
||||||
fclose(gameSave);
|
fclose(gameSave);
|
||||||
memcpy(tileMap, gameState.tileMap, sizeof(tileMap));
|
|
||||||
memcpy(plr, &gameState.player, sizeof(gameState.player));
|
memcpy(plr, &gameState.player, sizeof(gameState.player));
|
||||||
|
memcpy(tileMap, gameState.tileMap, sizeof(tileMap));
|
||||||
|
memcpy(backgroundMap, gameState.backgroundTileMap, sizeof(backgroundMap));
|
||||||
|
memcpy(audioData.synthVoices, gameState.voices, sizeof(gameState.voices));
|
||||||
|
plr->cursor.targetTile = NULL;
|
||||||
|
plr->cursor.prevTargetTile = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveGameState(char *filename, Player *plr) {
|
void saveGameState(char *filename, Player *plr) {
|
||||||
memcpy(&gameState.player, plr, sizeof(gameState.player));
|
memcpy(&gameState.player, plr, sizeof(gameState.player));
|
||||||
memcpy(gameState.tileMap, tileMap, sizeof(gameState.tileMap));
|
memcpy(gameState.tileMap, tileMap, sizeof(gameState.tileMap));
|
||||||
|
memcpy(gameState.backgroundTileMap, backgroundMap, sizeof(gameState.backgroundTileMap));
|
||||||
|
memcpy(gameState.voices, audioData.synthVoices, sizeof(gameState.voices));
|
||||||
|
|
||||||
FILE *gameSave = fopen(filename, "wb");
|
FILE *gameSave = fopen(filename, "wb");
|
||||||
if (!gameSave) {
|
if (!gameSave) {
|
||||||
@@ -51,7 +69,7 @@ const int delayNeeded = 1000 / targetFPS;
|
|||||||
#define smallerFont fonts[2]
|
#define smallerFont fonts[2]
|
||||||
#define smallestFont fonts[3]
|
#define smallestFont fonts[3]
|
||||||
|
|
||||||
const char *autosaveName = "autosave.dat";
|
char *autosaveName = "autosave.dat";
|
||||||
|
|
||||||
|
|
||||||
unsigned long frames = 0;
|
unsigned long frames = 0;
|
||||||
@@ -66,6 +84,8 @@ void msleep(unsigned int milliseconds) {
|
|||||||
|
|
||||||
SDL_GLContext glContext;
|
SDL_GLContext glContext;
|
||||||
|
|
||||||
|
void genInitMap();
|
||||||
|
|
||||||
int init() {
|
int init() {
|
||||||
//Initialize SDL
|
//Initialize SDL
|
||||||
|
|
||||||
@@ -75,7 +95,9 @@ int init() {
|
|||||||
screenRect.w = DISPLAY_WIDTH;
|
screenRect.w = DISPLAY_WIDTH;
|
||||||
screenRect.h = DISPLAY_HEIGHT;
|
screenRect.h = DISPLAY_HEIGHT;
|
||||||
|
|
||||||
srand(0);
|
srand(time(NULL));
|
||||||
|
|
||||||
|
memset(tileMap, 0, sizeof(tileMap));
|
||||||
|
|
||||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
||||||
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
|
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
|
||||||
@@ -107,8 +129,17 @@ int init() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initAtlas(mainRenderer);
|
||||||
|
|
||||||
loadTiles(mainRenderer);
|
loadTiles(mainRenderer);
|
||||||
loadItems(mainRenderer);
|
loadItems(mainRenderer);
|
||||||
|
setupTiles();
|
||||||
|
|
||||||
|
for (ItemType i = 0; i < ITEMREGISTRY_SIZE; i++) {
|
||||||
|
if (strlen(ItemRegistry[i].name)) {
|
||||||
|
printf("%d -> %s\n", i, ItemRegistry[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Create OpenGL context
|
// Create OpenGL context
|
||||||
glContext = SDL_GL_CreateContext(window);
|
glContext = SDL_GL_CreateContext(window);
|
||||||
if (!glContext) {
|
if (!glContext) {
|
||||||
@@ -119,21 +150,24 @@ int init() {
|
|||||||
// Use OpenGL context
|
// Use OpenGL context
|
||||||
SDL_GL_MakeCurrent(window, glContext); // Make sure OpenGL context is current before any OpenGL rendering
|
SDL_GL_MakeCurrent(window, glContext); // Make sure OpenGL context is current before any OpenGL rendering
|
||||||
|
|
||||||
|
audioData.playerRect = &player.rect;
|
||||||
|
audioData.maxPanDistance = DISPLAY_WIDTH / 2;
|
||||||
|
|
||||||
SDL_AudioSpec spec = {0};
|
SDL_AudioSpec spec = {0};
|
||||||
spec.freq = SAMPLE_RATE;
|
spec.freq = SAMPLE_RATE;
|
||||||
spec.format = AUDIO_F32SYS;
|
spec.format = AUDIO_F32;
|
||||||
spec.channels = 1;
|
spec.channels = 2;
|
||||||
spec.samples = 4096;
|
spec.samples = 4096;
|
||||||
spec.callback = audio_callback;
|
spec.callback = audio_callback;
|
||||||
spec.userdata = &audioData;
|
spec.userdata = &audioData;
|
||||||
|
|
||||||
SDL_AudioDeviceID dev = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0);
|
// SDL_AudioDeviceID dev = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0);
|
||||||
if (dev == 0) {
|
// if (dev == 0) {
|
||||||
printf("Failed to open audio: %s\n", SDL_GetError());
|
// printf("Failed to open audio: %s\n", SDL_GetError());
|
||||||
SDL_Quit();
|
// SDL_Quit();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
SDL_PauseAudioDevice(dev, 0);
|
// SDL_PauseAudioDevice(dev, 1);
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(mainRenderer);
|
SDL_RenderClear(mainRenderer);
|
||||||
@@ -150,6 +184,10 @@ int init() {
|
|||||||
|
|
||||||
initPlayer(&player);
|
initPlayer(&player);
|
||||||
|
|
||||||
|
for (ItemType i = 0; i < 13; i++) {
|
||||||
|
player.inventory.hotKeySlots[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
initTiles();
|
initTiles();
|
||||||
|
|
||||||
//generateTestMap();
|
//generateTestMap();
|
||||||
@@ -163,20 +201,22 @@ int render() {
|
|||||||
SDL_RenderClear(mainRenderer);
|
SDL_RenderClear(mainRenderer);
|
||||||
|
|
||||||
SDL_Rect rect2;
|
SDL_Rect rect2;
|
||||||
rect2.x = 20;
|
rect2.x = 0;
|
||||||
rect2.y = 20;
|
rect2.y = 0;
|
||||||
rect2.w = 0;
|
rect2.w = 0;
|
||||||
rect2.h = 0;
|
rect2.h = 0;
|
||||||
|
|
||||||
renderAllTiles(mainRenderer, player.rect);
|
renderAllTiles(mainRenderer, player.rect);
|
||||||
|
|
||||||
SDL_RenderCopy(mainRenderer, tilesTexture, &screenRect, &screenRect);
|
|
||||||
SDL_RenderCopy(mainRenderer, itemsTexture, &screenRect, &screenRect);
|
|
||||||
SDL_RenderCopy(mainRenderer, entityTexture, &screenRect, &screenRect);
|
|
||||||
SDL_RenderCopy(mainRenderer, hudTexture, &screenRect, &screenRect);
|
|
||||||
|
|
||||||
renderPlayer(&player);
|
renderPlayer(&player);
|
||||||
|
|
||||||
|
// SDL_RenderCopy(mainRenderer, backgroundTexture, &screenRect, &screenRect);
|
||||||
|
// SDL_RenderCopy(mainRenderer, tilesTexture, &screenRect, &screenRect);
|
||||||
|
// SDL_RenderCopy(mainRenderer, itemsTexture, &screenRect, &screenRect);
|
||||||
|
// SDL_RenderCopy(mainRenderer, entityTexture, &screenRect, &screenRect);
|
||||||
|
// SDL_RenderCopy(mainRenderer, hudTexture, &screenRect, &screenRect);
|
||||||
|
SDL_QueryTexture(atlasTexture, NULL, NULL, &rect2.w, &rect2.h);
|
||||||
|
SDL_RenderCopy(mainRenderer, atlasTexture, &rect2, &rect2);
|
||||||
|
|
||||||
|
|
||||||
SDL_RenderPresent(mainRenderer);
|
SDL_RenderPresent(mainRenderer);
|
||||||
frames++;
|
frames++;
|
||||||
@@ -206,11 +246,11 @@ int processEvent(SDL_Event e) {
|
|||||||
speed = speed == 0 ? 0.004f : 0;
|
speed = speed == 0 ? 0.004f : 0;
|
||||||
break;
|
break;
|
||||||
case SDLK_r:
|
case SDLK_r:
|
||||||
if (player.cursor.canReach && player.cursor.targetTile->type == TYPE_BELT) {
|
if (player.cursor.canReach && player.cursor.targetTile->type != TYPE_AIR) {
|
||||||
player.cursor.direction = player.cursor.targetTile->direction;
|
player.cursor.direction = player.cursor.targetTile->direction;
|
||||||
}
|
}
|
||||||
player.cursor.direction = (player.cursor.direction + 2) % ORIENT_DIRECTION_COUNT;
|
player.cursor.direction = (player.cursor.direction + 2) % ORIENT_DIRECTION_COUNT;
|
||||||
if (player.cursor.canReach && player.cursor.targetTile->type == TYPE_BELT) {
|
if (player.cursor.canReach) {
|
||||||
player.cursor.targetTile->direction = player.cursor.direction;
|
player.cursor.targetTile->direction = player.cursor.direction;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -220,6 +260,12 @@ int processEvent(SDL_Event e) {
|
|||||||
case SDLK_F3:
|
case SDLK_F3:
|
||||||
debugMode = !debugMode;
|
debugMode = !debugMode;
|
||||||
break;
|
break;
|
||||||
|
case SDLK_F4:
|
||||||
|
Tile *tile = &tileMap[playerTileY][playerTileX];
|
||||||
|
break;
|
||||||
|
case SDLK_LALT:
|
||||||
|
itemViewing = !itemViewing;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -274,7 +320,6 @@ void processMousePosition() {
|
|||||||
if (player.cursor.targetTile->type < tileTypeIndex) {
|
if (player.cursor.targetTile->type < tileTypeIndex) {
|
||||||
player.inventory.slotCounts[player.cursor.targetTile->type]++;
|
player.inventory.slotCounts[player.cursor.targetTile->type]++;
|
||||||
}
|
}
|
||||||
if (player.cursor.targetTile->type == TYPE_BELT) {
|
|
||||||
for (int lane = 0; lane < 2; lane++) {
|
for (int lane = 0; lane < 2; lane++) {
|
||||||
if (player.cursor.targetTile->items[lane].type != 0) {
|
if (player.cursor.targetTile->items[lane].type != 0) {
|
||||||
int itemType = player.cursor.targetTile->items[lane].type;
|
int itemType = player.cursor.targetTile->items[lane].type;
|
||||||
@@ -284,7 +329,6 @@ void processMousePosition() {
|
|||||||
player.cursor.targetTile->items[lane].type = 0;
|
player.cursor.targetTile->items[lane].type = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
player.cursor.targetTile->type = TYPE_AIR;
|
player.cursor.targetTile->type = TYPE_AIR;
|
||||||
player.cursor.breakingProgress = 0;
|
player.cursor.breakingProgress = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -311,6 +355,18 @@ void processMousePosition() {
|
|||||||
player.cursor.windowY = (player.cursor.windowY - viewport.y) * DISPLAY_HEIGHT / viewport.h;
|
player.cursor.windowY = (player.cursor.windowY - viewport.y) * DISPLAY_HEIGHT / viewport.h;
|
||||||
player.cursor.tileX = (player.cursor.windowX + player.rect.x) / TILE_SIZE - (DISPLAY_WIDTH / TILE_SIZE / 2);
|
player.cursor.tileX = (player.cursor.windowX + player.rect.x) / TILE_SIZE - (DISPLAY_WIDTH / TILE_SIZE / 2);
|
||||||
player.cursor.tileY = (player.cursor.windowY + player.rect.y) / TILE_SIZE - (DISPLAY_HEIGHT / TILE_SIZE / 2);
|
player.cursor.tileY = (player.cursor.windowY + player.rect.y) / TILE_SIZE - (DISPLAY_HEIGHT / TILE_SIZE / 2);
|
||||||
|
if (player.cursor.tileX < 0) {
|
||||||
|
player.cursor.tileX = 0;
|
||||||
|
}
|
||||||
|
if (player.cursor.tileY < 0) {
|
||||||
|
player.cursor.tileY = 0;
|
||||||
|
}
|
||||||
|
if (player.cursor.tileX >= MAP_WIDTH) {
|
||||||
|
player.cursor.tileX = MAP_WIDTH - 1;
|
||||||
|
}
|
||||||
|
if (player.cursor.tileY >= MAP_HEIGHT) {
|
||||||
|
player.cursor.tileY = MAP_HEIGHT - 1;
|
||||||
|
}
|
||||||
player.cursor.prevTargetTile = player.cursor.targetTile;
|
player.cursor.prevTargetTile = player.cursor.targetTile;
|
||||||
player.cursor.targetTile = &tileMap[player.cursor.tileY][player.cursor.tileX];
|
player.cursor.targetTile = &tileMap[player.cursor.tileY][player.cursor.tileX];
|
||||||
|
|
||||||
@@ -329,7 +385,7 @@ void processKeyboardHeld() {
|
|||||||
int cameraSpeed = playerSpeed;
|
int cameraSpeed = playerSpeed;
|
||||||
|
|
||||||
if (keyboardState[SDL_SCANCODE_LSHIFT] || keyboardState[SDL_SCANCODE_RSHIFT]) {
|
if (keyboardState[SDL_SCANCODE_LSHIFT] || keyboardState[SDL_SCANCODE_RSHIFT]) {
|
||||||
cameraSpeed *= 2;
|
cameraSpeed *= 8;
|
||||||
}
|
}
|
||||||
if (keyboardState[SDL_SCANCODE_LCTRL] || keyboardState[SDL_SCANCODE_RCTRL]) {
|
if (keyboardState[SDL_SCANCODE_LCTRL] || keyboardState[SDL_SCANCODE_RCTRL]) {
|
||||||
cameraSpeed /= 2;
|
cameraSpeed /= 2;
|
||||||
@@ -339,39 +395,57 @@ void processKeyboardHeld() {
|
|||||||
if (keyboardState[SDL_SCANCODE_W]) {
|
if (keyboardState[SDL_SCANCODE_W]) {
|
||||||
// Example: move up
|
// Example: move up
|
||||||
player.rect.y -= cameraSpeed;
|
player.rect.y -= cameraSpeed;
|
||||||
if (player.rect.y < (DISPLAY_HEIGHT / 2)) {
|
// if (player.rect.y < (DISPLAY_HEIGHT / 2)) {
|
||||||
player.rect.y = (DISPLAY_HEIGHT / 2);
|
// player.rect.y = (DISPLAY_HEIGHT / 2);
|
||||||
|
// }
|
||||||
|
if (player.rect.y < 0) {
|
||||||
|
player.rect.y = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyboardState[SDL_SCANCODE_S]) {
|
if (keyboardState[SDL_SCANCODE_S]) {
|
||||||
player.rect.y += cameraSpeed;
|
player.rect.y += cameraSpeed;
|
||||||
if (player.rect.y > (MAP_HEIGHT * TILE_SIZE) - (DISPLAY_HEIGHT / 2)) {
|
// if (player.rect.y > (MAP_HEIGHT * TILE_SIZE) - (DISPLAY_HEIGHT / 2)) {
|
||||||
player.rect.y = (MAP_HEIGHT * TILE_SIZE) - (DISPLAY_HEIGHT / 2);
|
// player.rect.y = (MAP_HEIGHT * TILE_SIZE) - (DISPLAY_HEIGHT / 2);
|
||||||
|
// }
|
||||||
|
if (player.rect.y > (MAP_HEIGHT * TILE_SIZE)) {
|
||||||
|
player.rect.y = (MAP_HEIGHT * TILE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyboardState[SDL_SCANCODE_A]) {
|
if (keyboardState[SDL_SCANCODE_A]) {
|
||||||
player.rect.x -= cameraSpeed;
|
player.rect.x -= cameraSpeed;
|
||||||
if (player.rect.x < (DISPLAY_WIDTH / 2)) {
|
// if (player.rect.x < (DISPLAY_WIDTH / 2)) {
|
||||||
player.rect.x = (DISPLAY_WIDTH / 2);
|
// player.rect.x = (DISPLAY_WIDTH / 2);
|
||||||
|
// }
|
||||||
|
if (player.rect.x < 0) {
|
||||||
|
player.rect.x = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyboardState[SDL_SCANCODE_D]) {
|
if (keyboardState[SDL_SCANCODE_D]) {
|
||||||
player.rect.x += cameraSpeed;
|
player.rect.x += cameraSpeed;
|
||||||
if (player.rect.x > (MAP_WIDTH * TILE_SIZE) - (DISPLAY_WIDTH / 2)) {
|
// if (player.rect.x > (MAP_WIDTH * TILE_SIZE) - (DISPLAY_WIDTH / 2)) {
|
||||||
player.rect.x = (MAP_WIDTH * TILE_SIZE) - (DISPLAY_WIDTH / 2);
|
// player.rect.x = (MAP_WIDTH * TILE_SIZE) - (DISPLAY_WIDTH / 2);
|
||||||
|
// }
|
||||||
|
if (player.rect.x > (MAP_WIDTH * TILE_SIZE)) {
|
||||||
|
player.rect.x = (MAP_WIDTH * TILE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboardState[SDL_SCANCODE_F]) {
|
if (keyboardState[SDL_SCANCODE_F]) {
|
||||||
for (int x = player.rect.x - 1; x < player.rect.x + 1; player.rect.x++) {
|
for (int x = playerTileX - 2; x < playerTileX + 2; x++) {
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int y = player.rect.y - 1; y < player.rect.y + 1; player.rect.y++) {
|
if (x >= MAP_WIDTH) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int y = playerTileY - 2; y < playerTileY + 2; y++) {
|
||||||
if (y < 0) {
|
if (y < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (y >= MAP_HEIGHT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Tile *t = &tileMap[y][x];
|
Tile *t = &tileMap[y][x];
|
||||||
if (t->type == TYPE_BELT) {
|
if (t->type == TYPE_BELT) {
|
||||||
for (uint8_t lane = 0; lane < 2; lane++) {
|
for (uint8_t lane = 0; lane < 2; lane++) {
|
||||||
@@ -431,8 +505,8 @@ void processKeyboardHeld() {
|
|||||||
} else if (keyboardState[SDL_SCANCODE_EQUALS]) {
|
} else if (keyboardState[SDL_SCANCODE_EQUALS]) {
|
||||||
slot = 13;
|
slot = 13;
|
||||||
}
|
}
|
||||||
if (slot > 0 && slot < itemRegistryIndex) {
|
if (slot > 0 && slot < sizeof(player.inventory.hotKeySlots) / sizeof(player.inventory.hotKeySlots[0])) {
|
||||||
setActivePlayerSlot(&player, slot);
|
setActivePlayerSlot(&player, player.inventory.hotKeySlots[slot]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,7 +515,9 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
if (status) {
|
if (status) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
loadGameState(autosaveName, &player);
|
if (loadGameState(autosaveName, &player)) {
|
||||||
|
genInitMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Hack to get window to stay up
|
//Hack to get window to stay up
|
||||||
@@ -460,6 +536,7 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
|
|
||||||
updateItems();
|
updateItems();
|
||||||
updatePlayer(&player);
|
updatePlayer(&player);
|
||||||
|
updateTiles();
|
||||||
status = render();
|
status = render();
|
||||||
if (status) {
|
if (status) {
|
||||||
return status;
|
return status;
|
||||||
@@ -486,3 +563,90 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main generator:
|
||||||
|
void genInitMap() {
|
||||||
|
const double terrainScale = 2;
|
||||||
|
const double humidityScale = 1;
|
||||||
|
const double oreScale = 2;
|
||||||
|
const int terrainOct = 4;
|
||||||
|
const int humidityOct = 4;
|
||||||
|
const int oreOct = 4;
|
||||||
|
|
||||||
|
int seedX = rand();
|
||||||
|
int seedY = rand();
|
||||||
|
int seedN = rand();
|
||||||
|
|
||||||
|
// Min/max trackers
|
||||||
|
double terrainMin = 1e9, terrainMax = -1e9;
|
||||||
|
double humidityMin = 1e9, humidityMax = -1e9;
|
||||||
|
double oreNrmMin = 1e9, oreNrmMax = -1e9;
|
||||||
|
for (uint16_t y = 0; y < MAP_HEIGHT; y++) {
|
||||||
|
for (uint16_t x = 0; x < MAP_WIDTH; x++) {
|
||||||
|
double terrain = pnoise2d(x + 1000 + seedX,
|
||||||
|
y + 1000 + seedY,
|
||||||
|
terrainScale, terrainOct, seedN);
|
||||||
|
double humidity = pnoise2d(x + seedX,
|
||||||
|
y + seedY,
|
||||||
|
humidityScale, humidityOct, seedN);
|
||||||
|
double oreNrm = pnoise2d(x + 9999 + seedX,
|
||||||
|
y + 1111 + seedY,
|
||||||
|
oreScale, oreOct, seedN);
|
||||||
|
|
||||||
|
// Track min/max
|
||||||
|
if (terrain < terrainMin) terrainMin = terrain;
|
||||||
|
if (terrain > terrainMax) terrainMax = terrain;
|
||||||
|
|
||||||
|
if (humidity < humidityMin) humidityMin = humidity;
|
||||||
|
if (humidity > humidityMax) humidityMax = humidity;
|
||||||
|
|
||||||
|
if (oreNrm < oreNrmMin) oreNrmMin = oreNrm;
|
||||||
|
if (oreNrm > oreNrmMax) oreNrmMax = oreNrm;
|
||||||
|
|
||||||
|
// [Same as your original terrain generation logic...]
|
||||||
|
BackgroundType baseType;
|
||||||
|
if (terrain < 0.30) {
|
||||||
|
baseType = (humidity < 0.5) ? BGType_WATER0 : BGType_WATER1;
|
||||||
|
} else if (terrain < 0.35) {
|
||||||
|
if (humidity < 0.3) baseType = BGType_SAND4;
|
||||||
|
else if (humidity < 0.6) baseType = BGType_SAND2;
|
||||||
|
else baseType = BGType_SAND7;
|
||||||
|
} else if (terrain < 0.7) {
|
||||||
|
double grassVal = (terrain - 0.35) / (0.70 - 0.35);
|
||||||
|
int idx = (int) (grassVal * 8.0);
|
||||||
|
if (idx >= 8) idx = 7;
|
||||||
|
if (humidity > 0.6 && ((rand() & 0xFF) < 10)) {
|
||||||
|
int flowerIdx = rand() % 4;
|
||||||
|
baseType = (BackgroundType) (BGType_GRASS_FLOWER0 + flowerIdx);
|
||||||
|
} else {
|
||||||
|
baseType = (BackgroundType) (BGType_GRASS0 + idx);
|
||||||
|
}
|
||||||
|
} else if (terrain < 0.85) {
|
||||||
|
int idx = rand() % 4;
|
||||||
|
baseType = (BackgroundType) (BGType_COBBLE0 + idx);
|
||||||
|
} else {
|
||||||
|
int idx = rand() % 4;
|
||||||
|
baseType = (BackgroundType) (BGType_TILES0 + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
BackgroundType finalType = baseType;
|
||||||
|
if (baseType != BGType_WATER0 && baseType != BGType_WATER1) {
|
||||||
|
if (oreNrm > 0.86) {
|
||||||
|
double sub = (oreNrm - 0.86) / (1.0 - 0.86);
|
||||||
|
if (sub < 0.25) finalType = BGType_PLATINUM_ORE;
|
||||||
|
else if (sub < 0.50) finalType = BGType_GOLD_ORE;
|
||||||
|
else if (sub < 0.80) finalType = BGType_SILVER_ORE;
|
||||||
|
else finalType = BGType_IRON_ORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backgroundMap[y][x].type = finalType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug printout
|
||||||
|
printf("Terrain Noise: min = %f, max = %f\n", terrainMin, terrainMax);
|
||||||
|
printf("Humidity Noise: min = %f, max = %f\n", humidityMin, humidityMax);
|
||||||
|
printf("Ore Normalized: min = %f, max = %f\n", oreNrmMin, oreNrmMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@ SDL_Rect targetItemRect;
|
|||||||
SDL_Color healthBarColor = {0, 240, 0, 255};
|
SDL_Color healthBarColor = {0, 240, 0, 255};
|
||||||
SDL_Color breakingBarColor = {128, 128, 0, 255};
|
SDL_Color breakingBarColor = {128, 128, 0, 255};
|
||||||
|
|
||||||
void setActivePlayerSlot(Player *plr, uint16_t activeSlotIndex) {
|
void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex) {
|
||||||
activeSlotIndex = activeSlotIndex % itemRegistryIndex;
|
activeSlotIndex = activeSlotIndex % itemRegistryIndex;
|
||||||
if (activeSlotIndex <= 0) {
|
if (activeSlotIndex <= 0) {
|
||||||
activeSlotIndex = 1;
|
activeSlotIndex = 1;
|
||||||
@@ -35,9 +35,8 @@ void setActivePlayerSlot(Player *plr, uint16_t activeSlotIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moveActivePlayerSlot(Player *plr, bool up, bool seek) {
|
void moveActivePlayerSlot(Player *plr, bool up, bool seek) {
|
||||||
if (seek) {
|
ItemType prevSlot = plr->inventory.activeSlotIndex;
|
||||||
uint16_t prevSlot = plr->inventory.activeSlotIndex;
|
ItemType newSlot = prevSlot;
|
||||||
uint16_t newSlot = prevSlot;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
newSlot = (newSlot + (up ? 1 : ITEMREGISTRY_SIZE - 1)) % ITEMREGISTRY_SIZE;
|
newSlot = (newSlot + (up ? 1 : ITEMREGISTRY_SIZE - 1)) % ITEMREGISTRY_SIZE;
|
||||||
@@ -46,24 +45,20 @@ void moveActivePlayerSlot(Player *plr, bool up, bool seek) {
|
|||||||
if (newSlot == prevSlot) break;
|
if (newSlot == prevSlot) break;
|
||||||
|
|
||||||
// Stop if we found a slot with count > 0
|
// Stop if we found a slot with count > 0
|
||||||
if (plr->inventory.slotCounts[newSlot] > 0 && newSlot != 0) break;
|
if (!strlen(ItemRegistry[newSlot].name)) continue;
|
||||||
|
if (newSlot == 0) continue;
|
||||||
|
if (seek) {
|
||||||
|
if (plr->inventory.slotCounts[newSlot] > 0) break;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} while (true);
|
} while (true);
|
||||||
plr->inventory.activeSlotIndex = newSlot;
|
plr->inventory.activeSlotIndex = newSlot;
|
||||||
} else {
|
|
||||||
if (plr->inventory.activeSlotIndex == 1 && !up) {
|
|
||||||
plr->inventory.activeSlotIndex = itemRegistryIndex - 1;
|
|
||||||
} else if (plr->inventory.activeSlotIndex == itemRegistryIndex - 1 && up) {
|
|
||||||
plr->inventory.activeSlotIndex = 1;
|
|
||||||
} else {
|
|
||||||
plr->inventory.activeSlotIndex =
|
|
||||||
(plr->inventory.activeSlotIndex + (up ? 1 : ITEMREGISTRY_SIZE - 1)) % ITEMREGISTRY_SIZE;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjustRect(SDL_Rect *rect, SDL_Rect playerRect) {
|
inline void adjustRect(SDL_Rect *rect, SDL_Rect playerRect) {
|
||||||
rect->x -= playerRect.x;
|
rect->x -= playerRect.x;
|
||||||
rect->y -= playerRect.y;
|
rect->y -= playerRect.y;
|
||||||
rect->x += DISPLAY_WIDTH / 2;
|
rect->x += DISPLAY_WIDTH / 2;
|
||||||
@@ -117,7 +112,11 @@ void initPlayer(Player *plr) {
|
|||||||
plr->rect.w = TILE_SIZE;
|
plr->rect.w = TILE_SIZE;
|
||||||
plr->rect.h = TILE_SIZE;
|
plr->rect.h = TILE_SIZE;
|
||||||
|
|
||||||
for (uint16_t ui = 0; ui < itemRegistryIndex; ui++) {
|
for (ItemType ui = 0; ui < tileTypeIndex; ui++) {
|
||||||
|
plr->inventory.slotCounts[ui] = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ItemType ui = ITEMREGISTRY_SIZE / 2; ui < itemRegistryIndex; ui++) {
|
||||||
plr->inventory.slotCounts[ui] = 64;
|
plr->inventory.slotCounts[ui] = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +171,7 @@ void renderPlayer(Player *plr) {
|
|||||||
SDL_SetRenderDrawColor(mainRenderer, plr->cursor.canReach ? 0 : 255, plr->cursor.canReach ? 255 : 0, 0, 128);
|
SDL_SetRenderDrawColor(mainRenderer, plr->cursor.canReach ? 0 : 255, plr->cursor.canReach ? 255 : 0, 0, 128);
|
||||||
DrawThickRect(mainRenderer, plr->cursor.targetTileRect, 4);
|
DrawThickRect(mainRenderer, plr->cursor.targetTileRect, 4);
|
||||||
|
|
||||||
uint16_t itemIndex = plr->inventory.activeSlotIndex;
|
ItemType itemIndex = plr->inventory.activeSlotIndex;
|
||||||
SDL_Texture *itemTex;
|
SDL_Texture *itemTex;
|
||||||
char itemStringCount[6];
|
char itemStringCount[6];
|
||||||
if (itemIndex < itemRegistryIndex) {
|
if (itemIndex < itemRegistryIndex) {
|
||||||
@@ -205,8 +204,12 @@ void renderPlayer(Player *plr) {
|
|||||||
renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 50, 200, 8, playerMaxHealth, plr->health,
|
renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 50, 200, 8, playerMaxHealth, plr->health,
|
||||||
healthBarColor, 4);
|
healthBarColor, 4);
|
||||||
|
|
||||||
|
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 - 70, 200, 8,
|
renderBar(mainRenderer, (DISPLAY_WIDTH / 2) - 128, DISPLAY_HEIGHT - 70, 200, 8,
|
||||||
getBreakTime(plr->cursor.targetTile->type), plr->cursor.breakingProgress, breakingBarColor, 4);
|
tempko, tempko2, breakingBarColor, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
|
||||||
@@ -215,7 +218,7 @@ void renderPlayer(Player *plr) {
|
|||||||
targetItemRect.y = DISPLAY_HEIGHT - 30 + TILE_SIZE / 4 + 3;
|
targetItemRect.y = DISPLAY_HEIGHT - 30 + TILE_SIZE / 4 + 3;
|
||||||
targetItemRect.x = TILE_SIZE / 4;
|
targetItemRect.x = TILE_SIZE / 4;
|
||||||
|
|
||||||
for (uint16_t i = 1; i < itemRegistryIndex; i++) {
|
for (ItemType i = 1; i < ITEMREGISTRY_SIZE; i++) {
|
||||||
itemTex = ItemRegistry[i].textureOnBelt[plr->cursor.direction];
|
itemTex = ItemRegistry[i].textureOnBelt[plr->cursor.direction];
|
||||||
if (itemTex == NULL) {
|
if (itemTex == NULL) {
|
||||||
itemTex = ItemRegistry[i].textureOnBelt[ORIENT_LEFT];
|
itemTex = ItemRegistry[i].textureOnBelt[ORIENT_LEFT];
|
||||||
@@ -228,7 +231,6 @@ void renderPlayer(Player *plr) {
|
|||||||
SDL_RenderCopy(mainRenderer, itemTex, NULL, &targetItemRect);
|
SDL_RenderCopy(mainRenderer, itemTex, NULL, &targetItemRect);
|
||||||
SDL_SetTextureColorMod(itemTex, 255, 255, 255);
|
SDL_SetTextureColorMod(itemTex, 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,
|
||||||
plr->inventory.slotCounts[i] > 0 ? 32 : 128, 255);
|
plr->inventory.slotCounts[i] > 0 ? 32 : 128, 255);
|
||||||
@@ -240,6 +242,7 @@ void renderPlayer(Player *plr) {
|
|||||||
//targetItemRect.x += (TILE_SIZE / 2) + (TILE_SIZE / 4);
|
//targetItemRect.x += (TILE_SIZE / 2) + (TILE_SIZE / 4);
|
||||||
targetItemRect.x += TILE_SIZE;
|
targetItemRect.x += TILE_SIZE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(mainRenderer, originalTarget);
|
SDL_SetRenderTarget(mainRenderer, originalTarget);
|
||||||
}
|
}
|
@@ -28,12 +28,13 @@ void adjustRect(SDL_Rect *rect, SDL_Rect playerRect);
|
|||||||
|
|
||||||
#define playerMaxHealth 255
|
#define playerMaxHealth 255
|
||||||
|
|
||||||
typedef struct {
|
typedef struct PlayerInventory {
|
||||||
uint16_t slotCounts[ITEMREGISTRY_SIZE];
|
uint16_t slotCounts[ITEMREGISTRY_SIZE];
|
||||||
uint16_t activeSlotIndex;
|
ItemType activeSlotIndex;
|
||||||
|
ItemType hotKeySlots[13];
|
||||||
} PlayerInventory;
|
} PlayerInventory;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct PlayerCursor {
|
||||||
int windowX;
|
int windowX;
|
||||||
int windowY;
|
int windowY;
|
||||||
int tileX;
|
int tileX;
|
||||||
@@ -50,7 +51,7 @@ typedef struct {
|
|||||||
int breakingProgress;
|
int breakingProgress;
|
||||||
} PlayerCursor;
|
} PlayerCursor;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Player{
|
||||||
PlayerCursor cursor;
|
PlayerCursor cursor;
|
||||||
PlayerInventory inventory;
|
PlayerInventory inventory;
|
||||||
uint8_t health;
|
uint8_t health;
|
||||||
@@ -59,7 +60,7 @@ typedef struct {
|
|||||||
SDL_Rect rect;
|
SDL_Rect rect;
|
||||||
} Player;
|
} Player;
|
||||||
|
|
||||||
void setActivePlayerSlot(Player *plr, uint16_t activeSlotIndex);
|
void setActivePlayerSlot(Player *plr, ItemType activeSlotIndex);
|
||||||
|
|
||||||
void moveActivePlayerSlot(Player *plr, bool up, bool seek);
|
void moveActivePlayerSlot(Player *plr, bool up, bool seek);
|
||||||
|
|
||||||
|
11
tiles/belt.c
@@ -16,7 +16,7 @@ void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect player
|
|||||||
|
|
||||||
Tile *t = &tileMap[y][x];
|
Tile *t = &tileMap[y][x];
|
||||||
|
|
||||||
uint16_t tileType = t->type;
|
ItemType tileType = t->type;
|
||||||
|
|
||||||
SDL_Rect src1, src2, dst1, dst2;
|
SDL_Rect src1, src2, dst1, dst2;
|
||||||
|
|
||||||
@@ -59,11 +59,8 @@ void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect player
|
|||||||
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1);
|
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1);
|
||||||
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2);
|
SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBelt(Tile * tile) {
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, itemsTexture);
|
|
||||||
for (uint8_t lane = 0; lane < 2; lane++) {
|
|
||||||
if (t->items[lane].type != 0) {
|
|
||||||
renderItem(t->items[lane], renderer, lane, playerRect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -7,9 +7,12 @@
|
|||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <SDL2/SDL_image.h>
|
#include <SDL2/SDL_image.h>
|
||||||
#include "tile.h"
|
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
|
|
||||||
|
struct Tile;
|
||||||
|
|
||||||
void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect playerRect, SDL_Renderer *renderer);
|
void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Rect playerRect, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
void updateBelt(struct Tile * tile);
|
||||||
|
|
||||||
#endif //FACTORYGAME_BELT_H
|
#endif //FACTORYGAME_BELT_H
|
||||||
|
@@ -4,11 +4,48 @@
|
|||||||
|
|
||||||
#include "furnace.h"
|
#include "furnace.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
#include "../util/audio.h"
|
||||||
|
|
||||||
uint16_t getFurnaceNewItem(uint16_t sourceItem) {
|
const ItemType FurnaceRecipes[ITEMREGISTRY_SIZE] = {
|
||||||
uint16_t realItemIndex = sourceItem - tileTypeIndex - 1;
|
[IRON_ORE] = IRON_INGOT,
|
||||||
if (realItemIndex < 8) {
|
[SILVER_ORE] = SILVER_INGOT,
|
||||||
return sourceItem + 1;
|
[GOLD_ORE] = GOLD_INGOT,
|
||||||
|
[PLATINUM_ORE] = PLATINUM_INGOT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
||||||
|
tile->audioCh = getAvailableChannel();
|
||||||
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
|
audioData.synthVoices[tile->audioCh].volume = 1;
|
||||||
|
audioData.synthVoices[tile->audioCh].phase = 0;
|
||||||
|
audioData.synthVoices[tile->audioCh].sourceRect.x = TILE_SIZE * tile->x;
|
||||||
|
audioData.synthVoices[tile->audioCh].sourceRect.y = TILE_SIZE * tile->y;
|
||||||
|
audioData.synthVoices[tile->audioCh].waveform = WAVE_TRIANGLE;
|
||||||
|
audioData.synthVoices[tile->audioCh].frequency = 99;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
|
audioData.synthVoices[tile->audioCh].frequency++;
|
||||||
|
}
|
||||||
|
if (outItem->type == 0 && ++tile->miscVal >= targetOutItem.miscVal) {
|
||||||
|
if (tile->audioCh < NUM_SYNTH_VOICES) {
|
||||||
|
audioData.synthVoices[tile->audioCh].volume = 0;
|
||||||
|
}
|
||||||
|
tile->miscVal = 0;
|
||||||
|
inItem->type = 0;
|
||||||
|
outItem->type = targetOutItemType;
|
||||||
|
outItem->offset = -0.5f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
@@ -5,6 +5,14 @@
|
|||||||
#ifndef FACTORYGAME_FURNACE_H
|
#ifndef FACTORYGAME_FURNACE_H
|
||||||
#define FACTORYGAME_FURNACE_H
|
#define FACTORYGAME_FURNACE_H
|
||||||
|
|
||||||
|
#include "../items/item.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
|
extern const ItemType FurnaceRecipes[];
|
||||||
|
|
||||||
|
#define FURNACE_INPUT_SLOT 0
|
||||||
|
#define FURNACE_OUTPUT_SLOT 1
|
||||||
|
|
||||||
|
void updateFurnace(Tile * tile);
|
||||||
|
|
||||||
#endif //FACTORYGAME_FURNACE_H
|
#endif //FACTORYGAME_FURNACE_H
|
||||||
|
178
tiles/tile.c
@@ -5,18 +5,26 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
|
#include "furnace.h"
|
||||||
|
#include "../util/atlas.h"
|
||||||
|
|
||||||
int scrollFrame = 0;
|
int scrollFrame = 0;
|
||||||
unsigned long beltFrames = 0;
|
unsigned long beltFrames = 0;
|
||||||
|
|
||||||
|
SDL_Texture *backgroundTexture;
|
||||||
SDL_Texture *tilesTexture;
|
SDL_Texture *tilesTexture;
|
||||||
SDL_Texture *itemsTexture;
|
SDL_Texture *itemsTexture;
|
||||||
|
|
||||||
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
|
|
||||||
uint16_t tileTypeIndex = 0;
|
BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
|
|
||||||
|
uint16_t tileTypeIndex = 0;
|
||||||
|
uint16_t backgroundTileTypeIndex = 0;
|
||||||
|
|
||||||
|
TileTypeReg TileRegistry[TILEREGISTRY_SIZE];
|
||||||
|
BackgroundTileType BackgroundTileRegistry[TILEREGISTRY_SIZE];
|
||||||
|
|
||||||
TileType TileRegistry[TILEREGISTRY_SIZE];
|
|
||||||
|
|
||||||
void generateTestMap() {
|
void generateTestMap() {
|
||||||
for (int y = 0; y < DISPLAY_MAP_HEIGHT; y++) {
|
for (int y = 0; y < DISPLAY_MAP_HEIGHT; y++) {
|
||||||
@@ -32,7 +40,7 @@ void generateTestMap() {
|
|||||||
for (int y = 0; y < MAP_HEIGHT; y += 1) {
|
for (int y = 0; y < MAP_HEIGHT; y += 1) {
|
||||||
|
|
||||||
tileMap[y][x].type = TYPE_BELT;
|
tileMap[y][x].type = TYPE_BELT;
|
||||||
tileMap[y][x].frameOffset = 0;
|
tileMap[y][x].miscVal = 0;
|
||||||
//tileMap[y][x].direction = ((x + y) % 4 * 2) + 1;
|
//tileMap[y][x].direction = ((x + y) % 4 * 2) + 1;
|
||||||
//tileMap[y][x].direction = 5;
|
//tileMap[y][x].direction = 5;
|
||||||
tileMap[y][x].direction = (rand() % 4 * 2) + 1;
|
tileMap[y][x].direction = (rand() % 4 * 2) + 1;
|
||||||
@@ -58,26 +66,68 @@ void registerTile(char name[20], SDL_Renderer *renderer) {
|
|||||||
TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT] = createFlippedTexture(renderer, texture, SDL_FLIP_HORIZONTAL);
|
TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT] = createFlippedTexture(renderer, texture, SDL_FLIP_HORIZONTAL);
|
||||||
TileRegistry[tileTypeIndex].textures[ORIENT_UP] = createRotatedTexture(renderer, texture, 90);
|
TileRegistry[tileTypeIndex].textures[ORIENT_UP] = createRotatedTexture(renderer, texture, 90);
|
||||||
TileRegistry[tileTypeIndex].textures[ORIENT_DOWN] = createRotatedTexture(renderer, texture, 270);
|
TileRegistry[tileTypeIndex].textures[ORIENT_DOWN] = createRotatedTexture(renderer, texture, 270);
|
||||||
|
if (tileTypeIndex == 0) {
|
||||||
|
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_LEFT], 64);
|
||||||
|
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_RIGHT], 64);
|
||||||
|
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_UP], 64);
|
||||||
|
SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_DOWN], 64);
|
||||||
|
}
|
||||||
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_UP], SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], renderer);
|
||||||
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_RIGHT] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], renderer);
|
||||||
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_UP] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_UP], renderer);
|
||||||
|
TileRegistry[tileTypeIndex].atlasRects[ORIENT_DOWN] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], renderer);
|
||||||
|
|
||||||
TileRegistry[tileTypeIndex].type = tileTypeIndex;
|
TileRegistry[tileTypeIndex].type = tileTypeIndex;
|
||||||
TileRegistry[tileTypeIndex].breakTime = 15;
|
TileRegistry[tileTypeIndex].breakTime = 15;
|
||||||
|
|
||||||
tileTypeIndex++;
|
tileTypeIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void registerBackgroundTile(char name[20], SDL_Renderer *renderer) {
|
||||||
|
const char *dot = strchr(name, '.');
|
||||||
|
memcpy(BackgroundTileRegistry[backgroundTileTypeIndex].name, name, dot - name);
|
||||||
|
char texturePath[80];
|
||||||
|
snprintf(texturePath, 80, "./assets/backgrounds/%s", name);
|
||||||
|
SDL_Texture *texture = IMG_LoadTexture(renderer, texturePath);
|
||||||
|
BackgroundTileRegistry[backgroundTileTypeIndex].texture = texture;
|
||||||
|
SDL_SetTextureBlendMode(BackgroundTileRegistry[backgroundTileTypeIndex].texture, SDL_BLENDMODE_NONE);
|
||||||
|
BackgroundTileRegistry[backgroundTileTypeIndex].atlasRect = allocate_32x32(BackgroundTileRegistry[backgroundTileTypeIndex].texture, renderer);
|
||||||
|
|
||||||
|
BackgroundTileRegistry[backgroundTileTypeIndex].type = backgroundTileTypeIndex;
|
||||||
|
|
||||||
|
backgroundTileTypeIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void loadTiles(SDL_Renderer *renderer) {
|
void loadTiles(SDL_Renderer *renderer) {
|
||||||
iterateSortedDir("./assets/tiles", (DirEntryCallback) registerTile, renderer);
|
iterateSortedDir("./assets/tiles", (DirEntryCallback) registerTile, renderer);
|
||||||
// DIR *dir = opendir("./assets/tiles");
|
iterateSortedDir("./assets/backgrounds", (DirEntryCallback) registerBackgroundTile, renderer);
|
||||||
// if (dir) {
|
|
||||||
// struct dirent *entry;
|
}
|
||||||
// while ((entry = readdir(dir)) != NULL) {
|
|
||||||
// if (entry->d_name[0] == '.') {
|
void setupTiles() {
|
||||||
// continue;
|
TileRegistry[TYPE_AIR].breakTime = 0;
|
||||||
// }
|
TileRegistry[TYPE_BELT].itemMoves = true;
|
||||||
// registerTile(entry->d_name, mainRenderer);
|
for (uint16_t i = 0; i < ItemSlotCount; i++) {
|
||||||
// }
|
TileRegistry[TYPE_BELT].outputLane[i] = true;
|
||||||
// }
|
}
|
||||||
TileRegistry[0].breakTime = 0;
|
for (uint16_t l = 0; l < ItemSlotCount; l++) {
|
||||||
|
for (ItemType i = 0; i < itemRegistryIndex; i++) {
|
||||||
|
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_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getBreakTime(int type) {
|
uint16_t getBreakTime(int type) {
|
||||||
@@ -92,6 +142,9 @@ void initTiles() {
|
|||||||
screenRect.h);
|
screenRect.h);
|
||||||
tilesTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
tilesTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w,
|
||||||
screenRect.h);
|
screenRect.h);
|
||||||
|
backgroundTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
||||||
|
screenRect.w,
|
||||||
|
screenRect.h);
|
||||||
SDL_SetTextureBlendMode(itemsTexture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(itemsTexture, SDL_BLENDMODE_BLEND);
|
||||||
SDL_SetTextureBlendMode(tilesTexture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(tilesTexture, SDL_BLENDMODE_BLEND);
|
||||||
}
|
}
|
||||||
@@ -99,10 +152,14 @@ void initTiles() {
|
|||||||
void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||||
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer);
|
||||||
SDL_SetRenderTarget(renderer, itemsTexture);
|
|
||||||
SDL_RenderClear(renderer);
|
int tileSize = TILE_SIZE;
|
||||||
SDL_SetRenderTarget(renderer, tilesTexture);
|
|
||||||
SDL_RenderClear(renderer);
|
int minTileX = (playerRect.x / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2) - 1;
|
||||||
|
int maxTileX = (playerRect.x / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) + 1;
|
||||||
|
int minTileY = (playerRect.y / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2) - 1;
|
||||||
|
int maxTileY = (playerRect.y / TILE_SIZE) + (DISPLAY_MAP_HEIGHT / 2) + 1;
|
||||||
|
|
||||||
int scrollSpeed = 1; // pixels per step
|
int scrollSpeed = 1; // pixels per step
|
||||||
int scrollDelay = 1; // frames between steps
|
int scrollDelay = 1; // frames between steps
|
||||||
|
|
||||||
@@ -110,42 +167,83 @@ void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) {
|
|||||||
scrollFrame += scrollSpeed;
|
scrollFrame += scrollSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tileSize = TILE_SIZE;
|
// --- Render background tiles ---
|
||||||
for (int y = (playerRect.y / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2) - 1;
|
SDL_SetRenderTarget(renderer, backgroundTexture);
|
||||||
y < (playerRect.y / TILE_SIZE) + (DISPLAY_MAP_HEIGHT / 2) + 1; y++) {
|
SDL_RenderClear(renderer);
|
||||||
if (y < 0 || y >= MAP_HEIGHT) {
|
|
||||||
continue;
|
for (int y = minTileY; y < maxTileY; y++) {
|
||||||
|
if (y < 0 || y >= MAP_HEIGHT) continue;
|
||||||
|
for (int x = minTileX; x < maxTileX; x++) {
|
||||||
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
||||||
|
|
||||||
|
SDL_Rect dstRect = {
|
||||||
|
.x = x * TILE_SIZE,
|
||||||
|
.y = y * TILE_SIZE,
|
||||||
|
.w = TILE_SIZE,
|
||||||
|
.h = TILE_SIZE
|
||||||
|
};
|
||||||
|
adjustRect(&dstRect, playerRect);
|
||||||
|
|
||||||
|
BackgroundTile bt = backgroundMap[y][x];
|
||||||
|
SDL_Texture *tex = BackgroundTileRegistry[bt.type].texture;
|
||||||
|
if (tex != NULL) {
|
||||||
|
SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
||||||
}
|
}
|
||||||
for (int x = (playerRect.x / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2) - 1;
|
|
||||||
x < (playerRect.x / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) + 1; x++) {
|
|
||||||
if (x < 0 || x >= MAP_WIDTH) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
Tile t = tileMap[y][x];
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, tilesTexture);
|
SDL_SetRenderTarget(renderer, tilesTexture);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
for (int y = minTileY; y < maxTileY; y++) {
|
||||||
|
if (y < 0 || y >= MAP_HEIGHT) continue;
|
||||||
|
for (int x = minTileX; x < maxTileX; x++) {
|
||||||
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
||||||
|
|
||||||
|
SDL_Rect dstRect = {
|
||||||
|
.x = x * TILE_SIZE,
|
||||||
|
.y = y * TILE_SIZE,
|
||||||
|
.w = TILE_SIZE,
|
||||||
|
.h = TILE_SIZE
|
||||||
|
};
|
||||||
|
adjustRect(&dstRect, playerRect);
|
||||||
|
|
||||||
|
Tile t = tileMap[y][x];
|
||||||
switch (t.type) {
|
switch (t.type) {
|
||||||
case TYPE_BELT:
|
case TYPE_BELT:
|
||||||
renderBelt(x, y, tileSize, tileSize, t.direction, playerRect, renderer);
|
renderBelt(x, y, tileSize, tileSize, t.direction, playerRect, renderer);
|
||||||
break;
|
break;
|
||||||
default:
|
default: {
|
||||||
SDL_Rect dstRect;
|
|
||||||
dstRect.x = x * TILE_SIZE;
|
|
||||||
dstRect.y = y * TILE_SIZE;
|
|
||||||
dstRect.w = TILE_SIZE;
|
|
||||||
dstRect.h = TILE_SIZE;
|
|
||||||
adjustRect(&dstRect, playerRect);
|
|
||||||
SDL_Texture *tex = TileRegistry[t.type].textures[t.direction];
|
SDL_Texture *tex = TileRegistry[t.type].textures[t.direction];
|
||||||
if (tex == NULL) {
|
if (tex == NULL) tex = TileRegistry[t.type].textures[ORIENT_LEFT];
|
||||||
tex = TileRegistry[t.type].textures[ORIENT_LEFT];
|
|
||||||
}
|
|
||||||
if (tex != NULL) {
|
if (tex != NULL) {
|
||||||
SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
SDL_RenderCopy(renderer, tex, NULL, &dstRect);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
SDL_SetRenderTarget(renderer, itemsTexture);
|
||||||
if (t.type == TYPE_BELT) {
|
SDL_RenderClear(renderer);
|
||||||
|
for (int y = minTileY; y < maxTileY; y++) {
|
||||||
|
if (y < 0 || y >= MAP_HEIGHT) continue;
|
||||||
|
for (int x = minTileX; x < maxTileX; x++) {
|
||||||
|
if (x < 0 || x >= MAP_WIDTH) continue;
|
||||||
|
|
||||||
|
Tile t = tileMap[y][x];
|
||||||
|
if (t.type == TYPE_BELT || itemViewing) {
|
||||||
|
for (uint8_t lane = 0; lane < ItemSlotCount; lane++) {
|
||||||
|
if (t.items[lane].type != 0) {
|
||||||
|
renderItem(t.items[lane], renderer, lane, playerRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, oldTarget);
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateTiles() {
|
||||||
|
|
||||||
|
}
|
98
tiles/tile.h
@@ -5,15 +5,15 @@
|
|||||||
#ifndef FACTORYGAME_TILE_H
|
#ifndef FACTORYGAME_TILE_H
|
||||||
#define FACTORYGAME_TILE_H
|
#define FACTORYGAME_TILE_H
|
||||||
|
|
||||||
#include "belt.h"
|
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
#include "../items/item.h"
|
#include "../items/item.h"
|
||||||
|
//#include "../items/item.h"
|
||||||
|
|
||||||
#define MAP_WIDTH 600
|
#define MAP_WIDTH 100
|
||||||
#define MAP_HEIGHT 340
|
#define MAP_HEIGHT 100
|
||||||
|
|
||||||
#define DISPLAY_MAP_WIDTH 44
|
#define DISPLAY_MAP_WIDTH 60
|
||||||
#define DISPLAY_MAP_HEIGHT 22
|
#define DISPLAY_MAP_HEIGHT 31
|
||||||
|
|
||||||
#define TILE_SIZE 32
|
#define TILE_SIZE 32
|
||||||
|
|
||||||
@@ -22,42 +22,108 @@
|
|||||||
|
|
||||||
extern SDL_Texture *tilesTexture;
|
extern SDL_Texture *tilesTexture;
|
||||||
extern SDL_Texture *itemsTexture;
|
extern SDL_Texture *itemsTexture;
|
||||||
|
extern SDL_Texture *backgroundTexture;
|
||||||
|
|
||||||
extern int scrollFrame;
|
extern int scrollFrame;
|
||||||
extern unsigned long beltFrames;
|
extern unsigned long beltFrames;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t type;
|
#define ItemSlotCount 4
|
||||||
|
|
||||||
|
typedef enum BackgroundType {
|
||||||
|
BGType_WATER0,
|
||||||
|
BGType_WATER1,
|
||||||
|
BGType_GRASS0,
|
||||||
|
BGType_GRASS1,
|
||||||
|
BGType_GRASS2,
|
||||||
|
BGType_GRASS3,
|
||||||
|
BGType_GRASS4,
|
||||||
|
BGType_GRASS5,
|
||||||
|
BGType_GRASS6,
|
||||||
|
BGType_GRASS7,
|
||||||
|
BGType_GRASS_FLOWER0,
|
||||||
|
BGType_GRASS_FLOWER1,
|
||||||
|
BGType_GRASS_FLOWER2,
|
||||||
|
BGType_GRASS_FLOWER3,
|
||||||
|
BGType_SAND0,
|
||||||
|
BGType_SAND1,
|
||||||
|
BGType_SAND2,
|
||||||
|
BGType_SAND3,
|
||||||
|
BGType_SAND4,
|
||||||
|
BGType_SAND5,
|
||||||
|
BGType_SAND6,
|
||||||
|
BGType_SAND7,
|
||||||
|
BGType_TILES0,
|
||||||
|
BGType_TILES1,
|
||||||
|
BGType_TILES2,
|
||||||
|
BGType_TILES3,
|
||||||
|
BGType_COBBLE0,
|
||||||
|
BGType_COBBLE1,
|
||||||
|
BGType_COBBLE2,
|
||||||
|
BGType_COBBLE3,
|
||||||
|
BGType_PLATINUM_ORE,
|
||||||
|
BGType_GOLD_ORE,
|
||||||
|
BGType_SILVER_ORE,
|
||||||
|
BGType_IRON_ORE,
|
||||||
|
BGType_END
|
||||||
|
} BackgroundType;
|
||||||
|
|
||||||
|
typedef struct TileTypeReg {
|
||||||
|
ItemType type;
|
||||||
char name[20];
|
char name[20];
|
||||||
SDL_Texture *textures[ORIENT_DIRECTION_COUNT];
|
SDL_Texture *textures[ORIENT_DIRECTION_COUNT];
|
||||||
|
SDL_Rect atlasRects[ORIENT_DIRECTION_COUNT];
|
||||||
uint16_t breakTime;
|
uint16_t breakTime;
|
||||||
} TileType;
|
bool itemMoves;
|
||||||
|
bool allowedInItems[ItemSlotCount][ITEMREGISTRY_SIZE];
|
||||||
|
bool outputLane[ItemSlotCount];
|
||||||
|
} TileTypeReg;
|
||||||
|
|
||||||
#define TILEREGISTRY_SIZE 512
|
typedef struct BackgroundTileType {
|
||||||
|
ItemType type;
|
||||||
|
char name[20];
|
||||||
|
SDL_Texture *texture;
|
||||||
|
SDL_Rect atlasRect;
|
||||||
|
} BackgroundTileType;
|
||||||
|
|
||||||
extern TileType TileRegistry[TILEREGISTRY_SIZE];
|
typedef struct BackgroundTile {
|
||||||
|
BackgroundType type;
|
||||||
|
} BackgroundTile;
|
||||||
|
|
||||||
#define TYPE_AIR 0
|
#define TILEREGISTRY_SIZE 64
|
||||||
#define TYPE_BELT 2
|
|
||||||
|
extern BackgroundTileType BackgroundTileRegistry[TILEREGISTRY_SIZE];
|
||||||
|
|
||||||
|
extern TileTypeReg TileRegistry[TILEREGISTRY_SIZE];
|
||||||
|
|
||||||
void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect);
|
void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect);
|
||||||
|
|
||||||
typedef struct {
|
void updateTiles();
|
||||||
|
|
||||||
|
typedef struct Tile {
|
||||||
OrientDirection direction;
|
OrientDirection direction;
|
||||||
uint16_t type;
|
ItemType type;
|
||||||
int frameOffset;
|
int miscVal;
|
||||||
ItemOnBelt items[2];
|
ItemOnBelt items[ItemSlotCount];
|
||||||
|
uint16_t audioCh;
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
} Tile;
|
} Tile;
|
||||||
|
|
||||||
|
|
||||||
extern Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
extern Tile tileMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
|
|
||||||
|
extern BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH];
|
||||||
|
|
||||||
|
void setupTiles();
|
||||||
|
|
||||||
void generateTestMap();
|
void generateTestMap();
|
||||||
|
|
||||||
void loadTiles(SDL_Renderer *renderer);
|
void loadTiles(SDL_Renderer *renderer);
|
||||||
|
|
||||||
extern uint16_t tileTypeIndex;
|
extern uint16_t tileTypeIndex;
|
||||||
|
extern uint16_t backgroundTileTypeIndex;
|
||||||
|
|
||||||
|
|
||||||
uint16_t getBreakTime(int type);
|
uint16_t getBreakTime(int type);
|
||||||
|
|
||||||
|
13
tiles/tilecallbacks.c
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 1.6.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "tilecallbacks.h"
|
||||||
|
#include "furnace.h"
|
||||||
|
|
||||||
|
const UpdateTileCallback ItemTileCallbacks[TILEREGISTRY_SIZE] = {
|
||||||
|
[TYPE_AIR] = NULL,
|
||||||
|
[TYPE_BLOCK] = NULL,
|
||||||
|
[TYPE_BELT] = updateBelt,
|
||||||
|
[TYPE_FURNACE] = updateFurnace
|
||||||
|
};
|
14
tiles/tilecallbacks.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 1.6.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FACTORYGAME_TILECALLBACKS_H
|
||||||
|
#define FACTORYGAME_TILECALLBACKS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "tile.h"
|
||||||
|
|
||||||
|
typedef void (*UpdateTileCallback)(struct Tile *tile);
|
||||||
|
|
||||||
|
extern const UpdateTileCallback ItemTileCallbacks[];
|
||||||
|
#endif //FACTORYGAME_TILECALLBACKS_H
|
80
util/atlas.c
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 1.6.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "atlas.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
SDL_Texture *atlasTexture;
|
||||||
|
|
||||||
|
int atlasX = 0, atlasY = 0;
|
||||||
|
|
||||||
|
int tileIndex = 0; // Which 32x32 tile we're on
|
||||||
|
int quadrantIndex = 0; // Which 16x16 slot inside that tile
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SDL_Rect allocate_16x16(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
||||||
|
SDL_Texture * oldTarget = SDL_GetRenderTarget(renderer);
|
||||||
|
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||||
|
int tileX = tileIndex % ATLAS_TILES_PER_ROW;
|
||||||
|
int tileY = tileIndex / ATLAS_TILES_PER_ROW;
|
||||||
|
|
||||||
|
int dx = (quadrantIndex % 2) * QUADRANT_SIZE;
|
||||||
|
int dy = (quadrantIndex / 2) * QUADRANT_SIZE;
|
||||||
|
|
||||||
|
SDL_Rect destRect = {
|
||||||
|
tileX * TILE_SIZE + dx,
|
||||||
|
tileY * TILE_SIZE + dy,
|
||||||
|
QUADRANT_SIZE,
|
||||||
|
QUADRANT_SIZE
|
||||||
|
};
|
||||||
|
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
||||||
|
|
||||||
|
quadrantIndex++;
|
||||||
|
if (quadrantIndex >= 4) {
|
||||||
|
tileIndex++;
|
||||||
|
quadrantIndex = 0;
|
||||||
|
}
|
||||||
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
|
return destRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
||||||
|
SDL_Texture * oldTarget = SDL_GetRenderTarget(renderer);
|
||||||
|
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||||
|
// If we’re not at the start of a tile, skip to the next clean one
|
||||||
|
if (quadrantIndex != 0) {
|
||||||
|
tileIndex++;
|
||||||
|
quadrantIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tileX = tileIndex % ATLAS_TILES_PER_ROW;
|
||||||
|
int tileY = tileIndex / ATLAS_TILES_PER_ROW;
|
||||||
|
|
||||||
|
SDL_Rect destRect = {
|
||||||
|
tileX * TILE_SIZE,
|
||||||
|
tileY * TILE_SIZE,
|
||||||
|
TILE_SIZE,
|
||||||
|
TILE_SIZE
|
||||||
|
};
|
||||||
|
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
||||||
|
|
||||||
|
tileIndex++; // Move to next tile
|
||||||
|
// quadrantIndex stays 0 — new tile is fresh
|
||||||
|
SDL_SetRenderTarget(renderer, oldTarget);
|
||||||
|
return destRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initAtlas(SDL_Renderer *renderer) {
|
||||||
|
|
||||||
|
// Clear atlas with transparent
|
||||||
|
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
|
||||||
|
atlasTexture = SDL_CreateTexture(renderer,
|
||||||
|
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
||||||
|
ATLAS_SIZE, ATLAS_SIZE);
|
||||||
|
}
|
23
util/atlas.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 1.6.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FACTORYGAME_ATLAS_H
|
||||||
|
#define FACTORYGAME_ATLAS_H
|
||||||
|
|
||||||
|
#define ATLAS_SIZE 512
|
||||||
|
#define TILE_SIZE 32
|
||||||
|
#define QUADRANT_SIZE 16
|
||||||
|
#define ATLAS_TILES_PER_ROW (ATLAS_SIZE / TILE_SIZE)
|
||||||
|
|
||||||
|
#include "SDL2/SDL.h"
|
||||||
|
|
||||||
|
extern SDL_Texture *atlasTexture;
|
||||||
|
|
||||||
|
SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
SDL_Rect allocate_16x16(SDL_Texture *srcTexture, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
void initAtlas(SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
#endif //FACTORYGAME_ATLAS_H
|
107
util/audio.c
@@ -6,21 +6,93 @@
|
|||||||
|
|
||||||
AudioData audioData;
|
AudioData audioData;
|
||||||
|
|
||||||
|
uint16_t getAvailableChannel() {
|
||||||
|
for (uint16_t i = 0; i < NUM_SYNTH_VOICES; i++) {
|
||||||
|
if (audioData.synthVoices[i].volume == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: compute left/right gains from a pan value in [–1..+1]
|
||||||
|
// pan = –1.0 → full left (L=1, R=0)
|
||||||
|
// pan = +1.0 → full right (L=0, R=1)
|
||||||
|
// pan = 0.0 → center (L=R=1/sqrt(2) or just 0.707 to avoid clipping)
|
||||||
|
static void compute_stereo_gains(float pan, float *outL, float *outR) {
|
||||||
|
// Simple linear panning (no constant‐power law).
|
||||||
|
// If you prefer constant‐power, you could do:
|
||||||
|
// float angle = (pan + 1.0f) * (M_PI / 4.0f);
|
||||||
|
// *outL = cosf(angle);
|
||||||
|
// *outR = sinf(angle);
|
||||||
|
//
|
||||||
|
// Here we’ll just do linear:
|
||||||
|
pan = fmaxf(-1.0f, fminf(+1.0f, pan));
|
||||||
|
if (pan <= 0.0f) {
|
||||||
|
*outL = 1.0f;
|
||||||
|
*outR = 1.0f + pan; // pan is negative, so R < 1
|
||||||
|
} else {
|
||||||
|
*outL = 1.0f - pan; // pan is positive, so L < 1
|
||||||
|
*outR = 1.0f;
|
||||||
|
}
|
||||||
|
// Optionally, scale down both so we never exceed 1.0f / sqrt(2)
|
||||||
|
// e.g. *outL *= 0.7071f; *outR *= 0.7071f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This callback now writes stereo frames: interleaved L/R floats.
|
||||||
void audio_callback(void *userdata, Uint8 *stream, int len) {
|
void audio_callback(void *userdata, Uint8 *stream, int len) {
|
||||||
AudioData *audio = (AudioData *) userdata;
|
AudioData *audio = (AudioData *) userdata;
|
||||||
int samples = len / sizeof(float);
|
|
||||||
|
|
||||||
for (int i = 0; i < samples; i++) {
|
// 'len' is total bytes; each sample‐frame is 2 floats (L+R), i.e. 2 * sizeof(float).
|
||||||
float mix = 0.0f;
|
int frames = len / (2 * sizeof(float));
|
||||||
int activeVoices = 0;
|
|
||||||
|
|
||||||
|
// Zero out the entire output buffer (silence)
|
||||||
|
// We’ll accumulate into it.
|
||||||
|
// Each float is 4 bytes, so total floats = 2 * frames.
|
||||||
|
float *outBuf = (float *) stream;
|
||||||
|
for (int i = 0; i < 2 * frames; ++i) {
|
||||||
|
outBuf[i] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precompute the listener center
|
||||||
|
float listenerCx = audio->playerRect->x + audio->playerRect->w * 0.5f;
|
||||||
|
|
||||||
|
// For each synth voice, mix into the stereo buffer
|
||||||
for (int v = 0; v < NUM_SYNTH_VOICES; v++) {
|
for (int v = 0; v < NUM_SYNTH_VOICES; v++) {
|
||||||
SynthVoice *voice = &audio->synthVoices[v];
|
SynthVoice *voice = &audio->synthVoices[v];
|
||||||
if (voice->volume == 0 || voice->frequency == 0) continue;
|
if (voice->volume == 0 || voice->frequency == 0) {
|
||||||
|
continue; // skip silent or inactive voices
|
||||||
|
}
|
||||||
|
|
||||||
float sample;
|
// Compute source center X
|
||||||
|
float sourceCx = voice->sourceRect.x + voice->sourceRect.w * 0.5f;
|
||||||
|
float dx = sourceCx - listenerCx;
|
||||||
|
|
||||||
|
// Normalize for pan. If |dx| >= maxPanDistance → full left or full right.
|
||||||
|
float pan = dx / audio->maxPanDistance;
|
||||||
|
if (pan < -1.0f) pan = -1.0f;
|
||||||
|
if (pan > +1.0f) pan = +1.0f;
|
||||||
|
|
||||||
|
float gainL, gainR;
|
||||||
|
compute_stereo_gains(pan, &gainL, &gainR);
|
||||||
|
|
||||||
|
// Optional: You could also attenuate overall volume with distance
|
||||||
|
// float dist = fabsf(dx);
|
||||||
|
// float distanceAtten = 1.0f - fminf(dist / audio->maxPanDistance, 1.0f);
|
||||||
|
// float finalVolume = (voice->volume / 255.0f) * distanceAtten;
|
||||||
|
// But for now, we’ll just use voice->volume for amplitude.
|
||||||
|
|
||||||
|
float amp = (voice->volume / 255.0f);
|
||||||
|
|
||||||
|
// Phase increment per sample‐frame:
|
||||||
|
// (freq * 256) / SAMPLE_RATE tells how many phase steps per mono-sample.
|
||||||
|
// Because we’re writing stereo, we still advance phase once per frame.
|
||||||
|
uint8_t phaseInc = (uint8_t)((voice->frequency * 256) / SAMPLE_RATE);
|
||||||
|
|
||||||
|
// Mix into each frame
|
||||||
|
for (int i = 0; i < frames; i++) {
|
||||||
float t = (float) voice->phase / 255.0f * 2.0f - 1.0f;
|
float t = (float) voice->phase / 255.0f * 2.0f - 1.0f;
|
||||||
|
float sample;
|
||||||
switch (voice->waveform) {
|
switch (voice->waveform) {
|
||||||
default:
|
default:
|
||||||
case WAVE_SINE:
|
case WAVE_SINE:
|
||||||
@@ -33,18 +105,27 @@ void audio_callback(void *userdata, Uint8 *stream, int len) {
|
|||||||
sample = t;
|
sample = t;
|
||||||
break;
|
break;
|
||||||
case WAVE_TRIANGLE:
|
case WAVE_TRIANGLE:
|
||||||
sample = (t < 0) ? -t : t;
|
sample = (t < 0.0f) ? -t : t;
|
||||||
break;
|
break;
|
||||||
case WAVE_NOISE:
|
case WAVE_NOISE:
|
||||||
sample = ((float) rand() / RAND_MAX) * 2.0f - 1.0f;
|
sample = ((float) rand() / RAND_MAX) * 2.0f - 1.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
voice->phase += (uint8_t) ((voice->frequency * 256) / SAMPLE_RATE);
|
voice->phase += phaseInc;
|
||||||
mix += sample * (voice->volume / 255.0f);
|
|
||||||
activeVoices++;
|
// Interleaved index: left = 2*i, right = 2*i + 1
|
||||||
|
int idxL = 2 * i;
|
||||||
|
int idxR = 2 * i + 1;
|
||||||
|
|
||||||
|
// Accumulate into buffer
|
||||||
|
outBuf[idxL] += sample * amp * gainL;
|
||||||
|
outBuf[idxR] += sample * amp * gainR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
((float *) stream)[i] = (activeVoices > 0) ? mix / activeVoices : 0.0f;
|
// Note: We did not normalize by active voices here, because each voice already
|
||||||
}
|
// uses its own volume. If you still want an automatic “divide by N active voices”,
|
||||||
|
// you would need to track active voices per‐frame, which is relatively expensive.
|
||||||
|
// In practice, you manage the volume per voice so clipping doesn’t occur.
|
||||||
}
|
}
|
19
util/audio.h
@@ -11,9 +11,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define SAMPLE_RATE 44100
|
#define SAMPLE_RATE 44100
|
||||||
#define NUM_SYNTH_VOICES 3
|
#define NUM_SYNTH_VOICES 256
|
||||||
|
|
||||||
typedef enum {
|
typedef enum Waveform {
|
||||||
WAVE_SINE,
|
WAVE_SINE,
|
||||||
WAVE_SQUARE,
|
WAVE_SQUARE,
|
||||||
WAVE_SAWTOOTH,
|
WAVE_SAWTOOTH,
|
||||||
@@ -21,19 +21,24 @@ typedef enum {
|
|||||||
WAVE_NOISE
|
WAVE_NOISE
|
||||||
} Waveform;
|
} Waveform;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct SynthVoice {
|
||||||
uint8_t volume;
|
|
||||||
uint16_t frequency;
|
|
||||||
uint8_t phase;
|
|
||||||
Waveform waveform;
|
Waveform waveform;
|
||||||
|
uint8_t phase;
|
||||||
|
uint16_t frequency;
|
||||||
|
uint8_t volume;
|
||||||
|
SDL_Rect sourceRect;
|
||||||
} SynthVoice;
|
} SynthVoice;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct AudioData {
|
||||||
SynthVoice synthVoices[NUM_SYNTH_VOICES];
|
SynthVoice synthVoices[NUM_SYNTH_VOICES];
|
||||||
|
SDL_Rect *playerRect;
|
||||||
|
float maxPanDistance;
|
||||||
} AudioData;
|
} AudioData;
|
||||||
|
|
||||||
extern AudioData audioData;
|
extern AudioData audioData;
|
||||||
|
|
||||||
void audio_callback(void *userdata, Uint8 *stream, int len);
|
void audio_callback(void *userdata, Uint8 *stream, int len);
|
||||||
|
|
||||||
|
uint16_t getAvailableChannel();
|
||||||
|
|
||||||
#endif //RISCB_AUDIO_H
|
#endif //RISCB_AUDIO_H
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#define fontCount 4
|
#define fontCount 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct BitmapFont {
|
||||||
SDL_Texture *texture[256];
|
SDL_Texture *texture[256];
|
||||||
SDL_Surface *surface[256];
|
SDL_Surface *surface[256];
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
|
52
util/perlin.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
double rawnoise(int n) {
|
||||||
|
n = (n << 13) ^ n;
|
||||||
|
return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise2d(int x, int y, int octave, int seed) {
|
||||||
|
return rawnoise(x * 1619 + y * 31337 + octave * 3463 + seed * 13397);
|
||||||
|
}
|
||||||
|
|
||||||
|
double interpolate(double a, double b, double x) {
|
||||||
|
double f = (1 - cos(x * 3.141593)) * 0.5;
|
||||||
|
|
||||||
|
return a * (1 - f) + b * f;
|
||||||
|
}
|
||||||
|
|
||||||
|
double smooth2d(double x, double y, int octave, int seed) {
|
||||||
|
int intx = (int) x;
|
||||||
|
double fracx = x - intx;
|
||||||
|
int inty = (int) y;
|
||||||
|
double fracy = y - inty;
|
||||||
|
|
||||||
|
double v1 = noise2d(intx, inty, octave, seed);
|
||||||
|
double v2 = noise2d(intx + 1, inty, octave, seed);
|
||||||
|
double v3 = noise2d(intx, inty + 1, octave, seed);
|
||||||
|
double v4 = noise2d(intx + 1, inty + 1, octave, seed);
|
||||||
|
|
||||||
|
double i1 = interpolate(v1, v2, fracx);
|
||||||
|
double i2 = interpolate(v3, v4, fracx);
|
||||||
|
|
||||||
|
return interpolate(i1, i2, fracy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double pnoise2d(double x, double y, double persistence, int octaves, int seed) {
|
||||||
|
double total = 0.0;
|
||||||
|
double frequency = 1.0;
|
||||||
|
double amplitude = 1.0;
|
||||||
|
double max = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < octaves; i++) {
|
||||||
|
total += smooth2d(x * frequency, y * frequency, i, seed) * amplitude;
|
||||||
|
max += amplitude;
|
||||||
|
frequency /= 2.0;
|
||||||
|
amplitude *= persistence;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize to [0, 1]
|
||||||
|
return (total + max) / (2.0 * max);
|
||||||
|
}
|
10
util/perlin.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 1.6.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FACTORYGAME_PERLIN_H
|
||||||
|
#define FACTORYGAME_PERLIN_H
|
||||||
|
|
||||||
|
double pnoise2d(double x, double y, double persistence, int octaves, int seed);
|
||||||
|
|
||||||
|
#endif //FACTORYGAME_PERLIN_H
|
@@ -6,11 +6,13 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
//#include "font.h"
|
//#include "font.h"
|
||||||
|
|
||||||
|
|
||||||
//The window we'll be rendering to
|
//The window we'll be rendering to
|
||||||
SDL_Window *window = NULL;
|
SDL_Window *window = NULL;
|
||||||
volatile bool running = true;
|
volatile bool running = true;
|
||||||
|
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
|
bool itemViewing = false;
|
||||||
|
|
||||||
//The surface contained by the window
|
//The surface contained by the window
|
||||||
SDL_Renderer *mainRenderer = NULL;
|
SDL_Renderer *mainRenderer = NULL;
|
||||||
|
@@ -16,7 +16,7 @@ extern SDL_Renderer *mainRenderer;
|
|||||||
|
|
||||||
extern SDL_Rect screenRect;
|
extern SDL_Rect screenRect;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum OrientDirection{
|
||||||
ORIENT_LEFT_DOWN,
|
ORIENT_LEFT_DOWN,
|
||||||
ORIENT_LEFT,
|
ORIENT_LEFT,
|
||||||
ORIENT_LEFT_UP,
|
ORIENT_LEFT_UP,
|
||||||
@@ -29,6 +29,7 @@ typedef enum {
|
|||||||
} OrientDirection;
|
} OrientDirection;
|
||||||
|
|
||||||
extern bool debugMode;
|
extern bool debugMode;
|
||||||
|
extern bool itemViewing;
|
||||||
|
|
||||||
SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle);
|
SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle);
|
||||||
|
|
||||||
|