diff --git a/art/belt.aseprite b/art/belt.aseprite new file mode 100644 index 0000000..1ca8c12 Binary files /dev/null and b/art/belt.aseprite differ diff --git a/art/gen/belt_down.png b/art/gen/belt_down.png new file mode 100644 index 0000000..ee7371d Binary files /dev/null and b/art/gen/belt_down.png differ diff --git a/art/gen/belt_left.png b/art/gen/belt_left.png new file mode 100644 index 0000000..e9f978e Binary files /dev/null and b/art/gen/belt_left.png differ diff --git a/art/gen/belt_right.png b/art/gen/belt_right.png new file mode 100644 index 0000000..031efbf Binary files /dev/null and b/art/gen/belt_right.png differ diff --git a/art/gen/belt_up.png b/art/gen/belt_up.png new file mode 100644 index 0000000..4978207 Binary files /dev/null and b/art/gen/belt_up.png differ diff --git a/art/gen/tree.png b/art/gen/tree.png new file mode 100644 index 0000000..c91a082 Binary files /dev/null and b/art/gen/tree.png differ diff --git a/art/gen/wood.png b/art/gen/wood.png new file mode 100644 index 0000000..9dc833e Binary files /dev/null and b/art/gen/wood.png differ diff --git a/art/tree.aseprite b/art/tree.aseprite new file mode 100644 index 0000000..d77365d Binary files /dev/null and b/art/tree.aseprite differ diff --git a/art/wood.aseprite b/art/wood.aseprite new file mode 100644 index 0000000..b8d9846 Binary files /dev/null and b/art/wood.aseprite differ diff --git a/code/game/src/asset_setup.h b/code/game/src/asset_setup.h index 0bea9bd..b22b1ef 100644 --- a/code/game/src/asset_setup.h +++ b/code/game/src/asset_setup.h @@ -9,11 +9,14 @@ // 2) Add the asset to the asset list #include "assets_list.c" +// 3) Assign a texture (if applicable) +#include "texgen.c" + // NOTE(zaklaus): Now that your asset is registered, we // can use it in other systems // NOTE(zaklaus): Register a block -#include "blocks_list.c" +#include "blocks/blocks_list.c" // NOTE(zaklaus): Register an item #include "items_list.c" diff --git a/code/game/src/assets.h b/code/game/src/assets.h index fde2ad1..b494374 100644 --- a/code/game/src/assets.h +++ b/code/game/src/assets.h @@ -25,6 +25,13 @@ typedef enum { ASSET_HILL, ASSET_HILL_SNOW, ASSET_HOLE, + ASSET_WOOD, + ASSET_TREE, + + ASSET_BELT_LEFT, + ASSET_BELT_RIGHT, + ASSET_BELT_UP, + ASSET_BELT_DOWN, MAX_ASSETS, FORCE_ASSET_UINT16 = UINT16_MAX diff --git a/code/game/src/assets_list.c b/code/game/src/assets_list.c index c878b33..bc514f2 100644 --- a/code/game/src/assets_list.c +++ b/code/game/src/assets_list.c @@ -21,4 +21,10 @@ static asset assets[] = { ASSET_TEX(ASSET_HILL), ASSET_TEX(ASSET_HILL_SNOW), ASSET_TEX(ASSET_HOLE), + ASSET_TEX(ASSET_WOOD), + ASSET_TEX(ASSET_TREE), + ASSET_TEX(ASSET_BELT_LEFT), + ASSET_TEX(ASSET_BELT_RIGHT), + ASSET_TEX(ASSET_BELT_UP), + ASSET_TEX(ASSET_BELT_DOWN), }; diff --git a/code/game/src/gen/texgen.c b/code/game/src/gen/texgen.c index f8f689c..3dfff0b 100644 --- a/code/game/src/gen/texgen.c +++ b/code/game/src/gen/texgen.c @@ -25,6 +25,12 @@ Texture2D texgen_build_sprite(asset_id id) { case ASSET_HILL: return LoadImageEco("rock"); case ASSET_WATER: return LoadImageEco("water"); case ASSET_LAVA: return LoadImageEco("lava"); + case ASSET_WOOD: return LoadImageEco("wood"); + case ASSET_TREE: return LoadImageEco("tree"); + case ASSET_BELT_LEFT: return LoadImageEco("belt_left"); + case ASSET_BELT_RIGHT: return LoadImageEco("belt_right"); + case ASSET_BELT_UP: return LoadImageEco("belt_up"); + case ASSET_BELT_DOWN: return LoadImageEco("belt_down"); default: { Image img = GenImageColor(1, 1, RAYWHITE); diff --git a/code/game/src/items.c b/code/game/src/items.c index 0b4f65c..941decb 100644 --- a/code/game/src/items.c +++ b/code/game/src/items.c @@ -38,6 +38,7 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p) { item_desc *desc = &items[item_id]; if (it->quantity <= 0) return; switch (item_get_usage(item_id)) { + case UKIND_HOLD: /* NOOP */ break; case UKIND_PLACE:{ world_block_lookup l = world_block_from_realpos(p.x, p.y); if (world_chunk_place_block(l.chunk_id, l.id, blocks_find(desc->place.kind)) ) diff --git a/code/game/src/items.h b/code/game/src/items.h index a9d3845..44d3157 100644 --- a/code/game/src/items.h +++ b/code/game/src/items.h @@ -6,6 +6,7 @@ #include "modules/components.h" typedef enum { + UKIND_HOLD, UKIND_PLACE, UKIND_PLACE_ITEM, UKIND_END_PLACE, diff --git a/code/game/src/items_list.c b/code/game/src/items_list.c index f03cd70..16edde4 100644 --- a/code/game/src/items_list.c +++ b/code/game/src/items_list.c @@ -1,5 +1,12 @@ #include "items.h" +#define ITEM_HOLD(asset, qty)\ +{\ +.kind = asset,\ +.usage = UKIND_HOLD,\ +.max_quantity = qty,\ +} + #define ITEM_BLOCK(asset, qty, build_asset)\ {\ .kind = asset,\ @@ -19,4 +26,11 @@ static item_desc items[] = { }, ITEM_BLOCK(ASSET_DEMO_ICEMAKER, 64, ASSET_WATER), ITEM_SELF(ASSET_FENCE, 64), + ITEM_SELF(ASSET_WOOD, 64), + ITEM_HOLD(ASSET_TREE, 64), + + ITEM_SELF(ASSET_BELT_LEFT, 999), + ITEM_SELF(ASSET_BELT_RIGHT, 999), + ITEM_SELF(ASSET_BELT_UP, 999), + ITEM_SELF(ASSET_BELT_DOWN, 999), }; diff --git a/code/game/src/world/blocks.c b/code/game/src/world/blocks.c index 0a928ec..08288f6 100644 --- a/code/game/src/world/blocks.c +++ b/code/game/src/world/blocks.c @@ -27,6 +27,9 @@ typedef struct { float friction; float bounce; + float velx; + float vely; + // NOTE(zaklaus): viewer data uint16_t slot; } block; @@ -74,6 +77,14 @@ float blocks_get_bounce(uint8_t id) { return blocks[id].bounce; } +float blocks_get_velx(uint8_t id) { + return blocks[id].velx; +} + +float blocks_get_vely(uint8_t id) { + return blocks[id].vely; +} + void *blocks_get_img(uint8_t id) { return assets_get_tex(blocks[id].slot); } diff --git a/code/game/src/world/blocks.h b/code/game/src/world/blocks.h index 403356d..622f076 100644 --- a/code/game/src/world/blocks.h +++ b/code/game/src/world/blocks.h @@ -18,6 +18,8 @@ uint32_t blocks_get_flags(uint8_t id); float blocks_get_drag(uint8_t id); float blocks_get_friction(uint8_t id); float blocks_get_bounce(uint8_t id); +float blocks_get_velx(uint8_t id); +float blocks_get_vely(uint8_t id); // NOTE(zaklaus): viewer-related functions void *blocks_get_img(uint8_t id); diff --git a/code/game/src/world/blocks_list.c b/code/game/src/world/blocks_list.c index d4e8dd4..fbb7fed 100644 --- a/code/game/src/world/blocks_list.c +++ b/code/game/src/world/blocks_list.c @@ -15,4 +15,11 @@ static block blocks[] = { BLOCK(ASSET_WATER, 0, '~', .drag = 0.11f , .friction = 1.0f), BLOCK(ASSET_LAVA, BLOCK_FLAG_HAZARD, '!', .drag = 6.2f , .friction = 4.0f), BLOCK(ASSET_FENCE, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 1.0f), + BLOCK(ASSET_WOOD, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f), + BLOCK(ASSET_TREE, BLOCK_FLAG_COLLISION, '@', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f), + + BLOCK(ASSET_BELT_LEFT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = -90.0f), + BLOCK(ASSET_BELT_RIGHT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = 90.0f), + BLOCK(ASSET_BELT_UP, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = -90.0f), + BLOCK(ASSET_BELT_DOWN, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = 90.0f), }; diff --git a/code/game/src/world/world.c b/code/game/src/world/world.c index f900737..ee69597 100644 --- a/code/game/src/world/world.c +++ b/code/game/src/world/world.c @@ -174,8 +174,9 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) { librg_event_set(world.tracker, LIBRG_WRITE_UPDATE, tracker_write_update); world.data = zpl_malloc(sizeof(uint8_t)*world.size); + world.outer_data = zpl_malloc(sizeof(uint8_t)*world.size); - if (!world.data) { + if (!world.data || !world.outer_data) { return WORLD_ERROR_OUTOFMEM; } @@ -214,13 +215,15 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) { *c = world.data[(chk_y+y)*world.dim + (chk_x+x)]; c = &world.outer_block_mapping[i][(y*chunk_size)+x]; - *c = 0; + *c = world.outer_data[(chk_y+y)*world.dim + (chk_x+x)]; } } } zpl_mfree(world.data); + zpl_mfree(world.outer_data); world.data = NULL; + world.outer_data = NULL; zpl_printf("[INFO] Created a new server world\n"); diff --git a/code/game/src/world/world.h b/code/game/src/world/world.h index 78605fb..d8cea7b 100644 --- a/code/game/src/world/world.h +++ b/code/game/src/world/world.h @@ -32,6 +32,7 @@ typedef WORLD_PKT_WRITER(world_pkt_writer_proc); typedef struct { bool is_paused; uint8_t *data; + uint8_t *outer_data; uint32_t seed; uint32_t size; uint16_t chunk_size; diff --git a/code/game/src/world/worldgen/worldgen_test.c b/code/game/src/world/worldgen/worldgen_test.c index ebfb711..fa0c9f5 100644 --- a/code/game/src/world/worldgen/worldgen_test.c +++ b/code/game/src/world/worldgen/worldgen_test.c @@ -12,7 +12,7 @@ #include "items.h" #include "world/blocks_info.h" -#define WORLD_BLOCK_OBSERVER(name) uint8_t name(uint8_t id, uint32_t block_idx) +#define WORLD_BLOCK_OBSERVER(name) uint8_t name(uint8_t *data, uint8_t id, uint32_t block_idx) typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc); #define WORLD_PERLIN_FREQ 100 @@ -41,7 +41,7 @@ uint8_t worldgen_biome_find(uint32_t biome, uint32_t kind) { static world_data *world; -static void world_fill_rect(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) { +static void world_fill_rect(uint8_t *data, uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) { for (uint32_t cy=y; cy= world->dim) continue; @@ -49,19 +49,19 @@ static void world_fill_rect(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint uint32_t i = (cy*world->dim) + cx; if (proc) { - uint8_t new_id = (*proc)(id, i); + uint8_t new_id = (*proc)(data, id, i); if (new_id != BLOCK_INVALID) { id = new_id; } else continue; } - world->data[i] = id; + data[i] = id; } } } -static void world_fill_circle(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) { +static void world_fill_circle(uint8_t *data, uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) { for (uint32_t cy=y; cy= world->dim) continue; @@ -69,27 +69,27 @@ static void world_fill_circle(uint8_t id, uint32_t x, uint32_t y, uint32_t w, ui uint32_t i = (cy*world->dim) + cx; if (proc) { - uint8_t new_id = (*proc)(id, i); + uint8_t new_id = (*proc)(data, id, i); if (new_id != BLOCK_INVALID) { id = new_id; } else continue; } - world->data[i] = id; + data[i] = id; } } } -static void world_fill_rect_anchor(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) { +static void world_fill_rect_anchor(uint8_t *data, uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) { uint32_t w2 = (uint32_t)floorf(w*ax); uint32_t h2 = (uint32_t)floorf(h*ay); - world_fill_rect(id, x-w2, y-h2, w, h, proc); + world_fill_rect(data, id, x-w2, y-h2, w, h, proc); } static WORLD_BLOCK_OBSERVER(shaper) { uint32_t kind = id; - uint32_t old_kind = world->data[block_idx]; + uint32_t old_kind = data[block_idx]; if (kind == BLOCK_KIND_WALL && kind == old_kind) { return worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_HILL); @@ -101,29 +101,38 @@ static WORLD_BLOCK_OBSERVER(shaper) { return id; } -static uint8_t world_perlin_cond(uint32_t block_idx, double chance) { - uint32_t x = block_idx % world->dim; - uint32_t y = block_idx / world->dim; +static uint8_t world_perlin_cond_offset(uint32_t block_idx, double chance, uint32_t ofx, uint32_t ofy) { + uint32_t x = block_idx % world->dim + ofx; + uint32_t y = block_idx / world->dim + ofy; return perlin_fbm(world->seed, x, y, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance; } +static uint8_t world_perlin_cond(uint32_t block_idx, double chance) { + return world_perlin_cond_offset(block_idx, chance, 0, 0); +} + #if 1 static WORLD_BLOCK_OBSERVER(shaper_noise80) { - return world_perlin_cond(block_idx, 0.80) ? shaper(id, block_idx) : BLOCK_INVALID; + return world_perlin_cond(block_idx, 0.80) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise50) { - return world_perlin_cond(block_idx, 0.50) ? shaper(id, block_idx) : BLOCK_INVALID; + return world_perlin_cond(block_idx, 0.50) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise33) { - return world_perlin_cond(block_idx, 0.33) ? shaper(id, block_idx) : BLOCK_INVALID; + return world_perlin_cond(block_idx, 0.33) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise05) { - return world_perlin_cond(block_idx, 0.05) ? shaper(id, block_idx) : BLOCK_INVALID; + return world_perlin_cond(block_idx, 0.05) ? shaper(data, id, block_idx) : BLOCK_INVALID; } + +static WORLD_BLOCK_OBSERVER(shaper_noise05b) { + return world_perlin_cond_offset(block_idx, 0.05, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID; +} + #else static WORLD_BLOCK_OBSERVER(shaper_noise80) { return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID; @@ -145,6 +154,7 @@ static void world_fill_mountain(uint32_t x, uint32_t y) { #endif #define RAND_RANGE(x,y) (x + (int)rand()%(y-(x))) +#define RAND_RANGEF(x,y) ((float)RAND_RANGE(x,y)) int32_t worldgen_test(world_data *wld) { // TODO(zaklaus): pass world as an arg instead @@ -157,32 +167,34 @@ int32_t worldgen_test(world_data *wld) { uint8_t dirt_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_DIRT); uint8_t watr_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER); uint8_t lava_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_LAVA); + uint8_t tree_id = blocks_find(ASSET_TREE); srand(world->seed); // walls - world_fill_rect(wall_id, 0, 0, world->dim, world->dim, NULL); + world_fill_rect(world->data, wall_id, 0, 0, world->dim, world->dim, NULL); // ground - world_fill_rect(grnd_id, 1, 1, world->dim-2, world->dim-2, NULL); - world_fill_rect(dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05); + world_fill_rect(world->data, grnd_id, 1, 1, world->dim-2, world->dim-2, NULL); + world_fill_rect(world->data, dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05); + world_fill_rect(world->outer_data, tree_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05b); // water #if 1 for (int i=0; idim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80); + world_fill_rect_anchor(world->data, watr_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80); } #endif // ice rink #if 0 - world_fill_rect_anchor(watr_id, 450, 125, 10, 10, 0.0f, 0.0f, NULL); + world_fill_rect_anchor(world->data, watr_id, 450, 125, 10, 10, 0.0f, 0.0f, NULL); #endif // lava #if 1 for (int i=0; idim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80); + world_fill_rect_anchor(world->data, lava_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80); } #endif @@ -191,7 +203,7 @@ int32_t worldgen_test(world_data *wld) { #if 1 const uint32_t HILLS_SIZE = 21; for (int i=0; idim), RAND_RANGE(0, world->dim), RAND_RANGE(0,HILLS_SIZE), RAND_RANGE(0,HILLS_SIZE), 0.5f, 0.5f, shaper_noise50); + world_fill_rect_anchor(world->data, wall_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), RAND_RANGE(0,HILLS_SIZE), RAND_RANGE(0,HILLS_SIZE), 0.5f, 0.5f, shaper_noise50); } #endif @@ -201,8 +213,8 @@ int32_t worldgen_test(world_data *wld) { uint64_t e = vehicle_spawn(); Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL); - dest->x = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE); - dest->y = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE); + dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); } #endif @@ -212,17 +224,34 @@ int32_t worldgen_test(world_data *wld) { uint64_t e = item_spawn(ASSET_DEMO_ICEMAKER, 32); Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL); - dest->x = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE); - dest->y = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE); + dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); } for (int i=0; ix = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE); - dest->y = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE); + dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); } + + for (int i=0; ix = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + } + + for (int i=0; ix = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); + } + #endif return WORLD_ERROR_NONE; diff --git a/code/modules/modules/systems.c b/code/modules/modules/systems.c index 527b595..899d58d 100644 --- a/code/modules/modules/systems.c +++ b/code/modules/modules/systems.c @@ -142,8 +142,10 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) { world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y); float drag = zpl_clamp(blocks_get_drag(lookup.block_id), 0.0f, 1.0f); float friction = blocks_get_friction(lookup.block_id); - v[i].x = zpl_lerp(v[i].x, 0.0f, PHY_WALK_DRAG*drag*friction*safe_dt(it)); - v[i].y = zpl_lerp(v[i].y, 0.0f, PHY_WALK_DRAG*drag*friction*safe_dt(it)); + float velx = blocks_get_velx(lookup.block_id); + float vely = blocks_get_vely(lookup.block_id); + v[i].x = zpl_lerp(v[i].x, zpl_max(0.0f, zpl_abs(velx))*zpl_sign(velx), PHY_WALK_DRAG*drag*friction*safe_dt(it)); + v[i].y = zpl_lerp(v[i].y, zpl_max(0.0f, zpl_abs(vely))*zpl_sign(vely), PHY_WALK_DRAG*drag*friction*safe_dt(it)); } }