Compare commits

..
Author SHA1 Message Date
matt 8363560fd2 fix: make it compile 2025-10-06 23:13:46 +01:00
matt 31863b0d31 fix: import 2025-10-06 23:09:53 +01:00
declan 7f77d7ad52 npc and bandit dressup, bits of UI added, WIP NPC interaction 2025-10-06 23:08:15 +01:00
matt f18d9d2b0e feat: made hitboxes area dependent 2025-10-06 21:57:06 +01:00
matt c01a6be4e5 feat: Initial prop placement 2025-10-06 21:35:32 +01:00
matt f93b543924 chore: fix \n 2025-10-06 21:30:13 +01:00
matt 72a86ddb41 Merge remote-tracking branch 'origin' 2025-10-06 21:19:44 +01:00
matt 680d375b8c feat: Added portals 2025-10-06 21:07:55 +01:00
bulmanator 87d3c9087e Merge branch 'debug'
Fixed some warnings
2025-10-06 19:52:28 +01:00
bulmanator 0c33944721 Merge branch 'debug/world_change' of yibble.dev:bulmanator/ld58 into debug 2025-10-06 19:38:14 +01:00
bulmanator c1fb705f68 Fixed level saving and loading 2025-10-06 19:36:41 +01:00
matt be49003a8d Merge remote-tracking branch 'origin' 2025-10-06 19:32:12 +01:00
matt 7b7f088116 fix: save/load 2025-10-06 19:27:45 +01:00
bulmanator cb10bd10b6 Merge branch 'main' of yibble.dev:bulmanator/ld58 2025-10-06 17:55:32 +01:00
bulmanator a6577f520b Fixed ???
Some files have been renamed
2025-10-06 17:49:08 +01:00
declan d54b4df4c2 player health 2025-10-06 17:45:58 +01:00
declan fcc7adfb22 added badman shooting and reloading 2025-10-06 17:30:49 +01:00
73 changed files with 732 additions and 193 deletions

No files matched your search

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+1
View File
@@ -3,6 +3,7 @@
#define S(x) Str8_Wrap(sizeof(x) - sizeof(*(x)), (U8 *) (x)) #define S(x) Str8_Wrap(sizeof(x) - sizeof(*(x)), (U8 *) (x))
#define Sz(x) Str8_WrapZ((U8 *) (x)) #define Sz(x) Str8_WrapZ((U8 *) (x))
#define Sl(x) { sizeof(x) - sizeof(*(x)), (U8 *) (x) }
#define Sv(x) (int) (x).count, (x).data #define Sv(x) (int) (x).count, (x).data
#define Sf(arena, fmt, ...) Str8_Format(arena, fmt, ##__VA_ARGS__) #define Sf(arena, fmt, ...) Str8_Format(arena, fmt, ##__VA_ARGS__)
+44 -41
View File
@@ -151,6 +151,8 @@ void _D_Rect(D_Context *draw, D_RectOpts *opts) {
rect->texture = opts->texture; rect->texture = opts->texture;
F32 w, h;
rect->x = opts->p.x; rect->x = opts->p.x;
rect->y = opts->p.y; rect->y = opts->p.y;
@@ -177,11 +179,19 @@ void _D_Rect(D_Context *draw, D_RectOpts *opts) {
} }
if (opts->flags & D_RECT_IGNORE_ASPECT) { if (opts->flags & D_RECT_IGNORE_ASPECT) {
rect->w = opts->dim.w; w = opts->dim.w;
rect->h = opts->dim.h; h = opts->dim.h;
} }
else { else {
Vk_Image *image = &draw->images[opts->texture].image; Vk_Image *image = 0;
if (opts->texture >= draw->n_images) {
// @hack: first font texture
//
image = &draw->fonts->image;
}
else {
image = &draw->images[opts->texture].image;
}
F32 width = cast(F32) image->width; F32 width = cast(F32) image->width;
F32 height = cast(F32) image->height; F32 height = cast(F32) image->height;
@@ -191,53 +201,42 @@ void _D_Rect(D_Context *draw, D_RectOpts *opts) {
height *= (opts->uv.max.y - opts->uv.min.y); height *= (opts->uv.max.y - opts->uv.min.y);
} }
F32 aspect_w = (width > height) ? (width / height) : 1.0f; F32 aspect_w = (width > height) ? 1.0f : (width / height);
F32 aspect_h = (width > height) ? 1.0f : (height / width); F32 aspect_h = (width > height) ? (height / width) : 1.0f;
rect->w = opts->scale * aspect_w; w = opts->scale * aspect_w;
rect->h = opts->scale * aspect_h; h = opts->scale * aspect_h;
} }
if (opts->flags & D_RECT_FLIP_X) { w *= -1.0f; }
if (opts->flags & D_RECT_FLIP_Y) { h *= -1.0f; }
rect->w = w;
rect->h = h;
draw->n_rects += 1; draw->n_rects += 1;
} }
} }
void D_Text(D_Context *draw, D_Font *font, Str8 text, F32 x, F32 y) { void D_Text(D_Context *draw, D_Font *font, Str8 text, F32 x, F32 y) {
F32 xoff = x; F32 xoff = x;
local_persist B32 done = 0;
// @Todo: control scale
F32 scale = 1.0f / (font->ascent - font->descent);
for (S64 it = 0; it < text.count; ++it) { for (S64 it = 0; it < text.count; ++it) {
if (text.data[it] >= ' ' && text.data[it] <= '~') { if (text.data[it] >= ' ' && text.data[it] <= '~') {
D_Glyph *glyph = &font->glyphs[text.data[it] - ' ']; D_Glyph *glyph = &font->glyphs[text.data[it] - ' '];
V2f size; F32 image_scale = scale * Max(glyph->dim.w, glyph->dim.h);
size.w = (glyph->box.max.x - glyph->box.min.x); F32 advance = scale * glyph->advance;
size.h = (glyph->box.max.y - glyph->box.min.y);
V2f dim; V2f offset = V2f_Scale(glyph->offset, scale);
F32 scale = 150.0f / (font->ascent - font->descent); D_Rect(draw, xoff + offset.x, y + offset.y, .texture = font->id, .uv = glyph->box, .scale = image_scale, .flags = D_RECT_UV_ASPECT);
xoff += advance;
if (size.w > size.h) {
dim.w = scale * (size.w / size.h);
dim.h = scale;
}
else {
dim.w = scale;
dim.h = scale * (size.h / size.w);
}
// @Hardcode: need font index in font struct
D_Rect(draw, xoff, y, .texture = 0, .c = V4F(0, 1, 1, 1), .dim = dim, .flags = D_RECT_IGNORE_ASPECT);
D_Rect(draw, xoff, y, .texture = draw->n_images, .uv = glyph->box, .dim = dim, .flags = D_RECT_IGNORE_ASPECT);
xoff += (1.05f * dim.w); // glyph->advance; //+ glyph->offset.x;
if (!done) { printf(" %f (%f, %f)", xoff, dim.w, dim.h); }
} }
} }
if (!done) { printf("\n"); }
done = true;
} }
void D_FontLoad(D_Context *draw, Str8 name, F32 size) { void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
@@ -252,7 +251,7 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
stbtt_fontinfo info = { 0 }; stbtt_fontinfo info = { 0 };
stbtt_InitFont(&info, font_data.data, 0); stbtt_InitFont(&info, font_data.data, 0);
F32 scale = stbtt_ScaleForPixelHeight(&info, 20); F32 scale = stbtt_ScaleForPixelHeight(&info, 256);
U32 w = 512; U32 w = 512;
U32 h = 512; U32 h = 512;
@@ -268,14 +267,12 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
D_Font *font = M_ArenaPush(draw->arena, D_Font); D_Font *font = M_ArenaPush(draw->arena, D_Font);
font->px = size;
S32 asc, desc, line; S32 asc, desc, line;
stbtt_GetFontVMetrics(&info, &asc, &desc, &line); stbtt_GetFontVMetrics(&info, &asc, &desc, &line);
font->line_advance = cast(F32) line; font->line_advance = cast(F32) (scale * line);
font->ascent = cast(F32) asc; font->ascent = cast(F32) (scale * asc);
font->descent = cast(F32) desc; font->descent = cast(F32) (scale * desc);
font->glyphs = M_ArenaPush(draw->arena, D_Glyph, .count = count); font->glyphs = M_ArenaPush(draw->arena, D_Glyph, .count = count);
@@ -286,10 +283,14 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
S32 left, width; S32 left, width;
stbtt_GetCodepointHMetrics(&info, ' ' + it, &width, &left); stbtt_GetCodepointHMetrics(&info, ' ' + it, &width, &left);
glyph->box = R2F(V2F(chr->x0 / (F32) w, chr->y0 / (F32) h), V2F(chr->x1 / (F32) w, chr->y1 / (F32) h)); glyph->box.min = V2F(chr->x0 / (F32) w, chr->y0 / (F32) h);
glyph->box.max = V2F(chr->x1 / (F32) w, chr->y1 / (F32) h);
glyph->advance = glyph->box.max.x - glyph->box.min.x; //chr->xadvance * scale; glyph->advance = chr->xadvance;
glyph->offset = V2F(chr->xoff * scale, chr->yoff * scale); glyph->dim.w = cast(F32) (chr->x1 - chr->x0);
glyph->dim.h = cast(F32) (chr->y1 - chr->y0);
glyph->offset.x = (0.5f * glyph->dim.w) + chr->xoff;
glyph->offset.y = (0.5f * glyph->dim.h) + chr->yoff;
} }
Vk_Buffer *staging = &draw->staging; Vk_Buffer *staging = &draw->staging;
@@ -302,6 +303,8 @@ void D_FontLoad(D_Context *draw, Str8 name, F32 size) {
Vk_CommandBuffer *cmds = Vk_CommandBufferPush(); Vk_CommandBuffer *cmds = Vk_CommandBufferPush();
font->id = draw->n_images + draw->n_fonts;
font->image.width = w; font->image.width = w;
font->image.height = h; font->image.height = h;
+7 -2
View File
@@ -6,7 +6,10 @@
typedef struct D_Glyph D_Glyph; typedef struct D_Glyph D_Glyph;
struct D_Glyph { struct D_Glyph {
F32 advance; F32 advance;
V2f offset; V2f offset;
V2f dim;
R2f box; R2f box;
}; };
@@ -14,13 +17,13 @@ typedef struct D_Font D_Font;
struct D_Font { struct D_Font {
D_Font *next; D_Font *next;
F32 px; U32 id;
F32 line_advance; F32 line_advance;
F32 ascent; F32 ascent;
F32 descent; F32 descent;
F32 *kerning; F32 *kerning; // @incomplete: we don't load this
D_Glyph *glyphs; D_Glyph *glyphs;
Vk_Image image; Vk_Image image;
@@ -108,6 +111,8 @@ enum D_RectFlags {
D_RECT_IGNORE_ASPECT = (1 << 0), // by default only width is used as a "dimension" D_RECT_IGNORE_ASPECT = (1 << 0), // by default only width is used as a "dimension"
D_RECT_PER_VERTEX_COLOUR = (1 << 1), // split colours per vertex D_RECT_PER_VERTEX_COLOUR = (1 << 1), // split colours per vertex
D_RECT_UV_ASPECT = (1 << 2), // get the aspect from the uv rect rather than the full image D_RECT_UV_ASPECT = (1 << 2), // get the aspect from the uv rect rather than the full image
D_RECT_FLIP_X = (1 << 3),
D_RECT_FLIP_Y = (1 << 4)
}; };
typedef struct D_RectOpts D_RectOpts; typedef struct D_RectOpts D_RectOpts;
+134 -44
View File
@@ -24,6 +24,7 @@
#include "game/impl/world.c" #include "game/impl/world.c"
#include "game/impl/npc.c" #include "game/impl/npc.c"
#include "game/impl/bandit.c" #include "game/impl/bandit.c"
#include "game/impl/outfit.c"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -78,6 +79,8 @@ int main(int argc, char **argv)
game->draw.arena = arena; game->draw.arena = arena;
G_ImagesLoad(game); G_ImagesLoad(game);
//D_FontLoad(&game->draw, S("ubuntu"), 60);
G_PipelinesLoad(game); G_PipelinesLoad(game);
G_AudioLoad(game); G_AudioLoad(game);
@@ -95,12 +98,11 @@ int main(int argc, char **argv)
game->draw.camera = camera; game->draw.camera = camera;
World *world = M_ArenaPush(arena, World); World *world = M_ArenaPush(arena, World);
//LoadWorld(arena, world); LoadWorld(arena, world);
game->world = world; game->world = world;
world->arena = arena; world->arena = arena;
//world->navMesh = &TestNavMesh;
world->random = Random_Seed(29237489723847); world->random = Random_Seed(29237489723847);
world->npcCount = 127; world->npcCount = 12;
for(U32 i = 0; i < world->npcCount; i++) { for(U32 i = 0; i < world->npcCount; i++) {
NPC *npc1 = &world->npcs[i]; NPC *npc1 = &world->npcs[i];
npc1->collision.pos.x = 0; npc1->collision.pos.x = 0;
@@ -111,8 +113,9 @@ int main(int argc, char **argv)
npc1->mode = NPC_ACTION_WAITING; npc1->mode = NPC_ACTION_WAITING;
npc1->currentArea = WORLD_AREA_OUTSIDE; npc1->currentArea = WORLD_AREA_OUTSIDE;
npc1->waitTime = 0; npc1->waitTime = 0;
npc1->maxWaitTime = 5; npc1->maxWaitTime = 1;
npc1->currentNavNode = 0; npc1->currentNavNode = 0;
GenOutfit(&npc1->outfit,world,game);
} }
Bandit *badman = &world->bandit; Bandit *badman = &world->bandit;
@@ -125,17 +128,21 @@ int main(int argc, char **argv)
badman->waitTime = 0; badman->waitTime = 0;
badman->maxWaitTime = 2; badman->maxWaitTime = 2;
badman->poiCount = 2; badman->poiCount = 2;
badman->shootoutTimer = 1.5;
badman->agroRadius = 6.0;
badman->bullets = 6;
badman->shootDelay = 1;
badman->accuracyRange = 0.25;
badman->reloadTime = 2.5;
badman->reloadTimer = 0;
badman->pointsOfInterest[0] = 937; badman->pointsOfInterest[0] = 937;
badman->pointsOfInterest[1] = 12; badman->pointsOfInterest[1] = 12;
badman->outfitChoices = GenOutfit(&badman->outfit, world, game);
badman->currentArea = WORLD_AREA_OUTSIDE;
world->npcPOI[0] = 100; world->npcPOI[0] = 100;
world->player.world = world;
world->player.pos.x = 0; PlayerInit(game, &world->player);
world->player.pos.y = 0;
world->player.bulletsLoaded = PLAYER_BULLET_COUNT;
world->player.reloadTimer = 0;
world->player.currentArea = WORLD_AREA_OUTSIDE;
world->map = map;
world->tileTypes = M_ArenaPush(arena, World_Tile, .count=WORLD_TILE_TYPE_MAX); world->tileTypes = M_ArenaPush(arena, World_Tile, .count=WORLD_TILE_TYPE_MAX);
world->tileTypes[0].rotation=0; world->tileTypes[0].rotation=0;
@@ -171,9 +178,9 @@ int main(int argc, char **argv)
world->propTypes = M_ArenaPush(arena, World_PropType, .count=WORLD_PROP_TYPE_MAX); world->propTypes = M_ArenaPush(arena, World_PropType, .count=WORLD_PROP_TYPE_MAX);
world->propTypes[0].tag=S("rug0"); world->propTypes[0].tag=S("rug0");
world->propTypes[0].scale=1; world->propTypes[0].scale=3;
world->propTypes[1].tag=S("rug1"); world->propTypes[1].tag=S("rug1");
world->propTypes[1].scale=1; world->propTypes[1].scale=3;
world->propTypes[2].tag=S("skull"); world->propTypes[2].tag=S("skull");
world->propTypes[2].scale=1; world->propTypes[2].scale=1;
world->propTypes[3].tag = S("table"); world->propTypes[3].tag = S("table");
@@ -181,17 +188,17 @@ int main(int argc, char **argv)
world->propTypes[4].tag = S("barrel"); world->propTypes[4].tag = S("barrel");
world->propTypes[4].scale=1; world->propTypes[4].scale=1;
world->propTypes[5].tag = S("can"); world->propTypes[5].tag = S("can");
world->propTypes[5].scale=1; world->propTypes[5].scale=0.5;
world->propTypes[6].tag = S("candle"); world->propTypes[6].tag = S("candle");
world->propTypes[6].scale=1; world->propTypes[6].scale=0.5;
world->propTypes[7].tag = S("clock"); world->propTypes[7].tag = S("clock");
world->propTypes[7].scale=1; world->propTypes[7].scale=1.5;
world->propTypes[8].tag = S("log_pile"); world->propTypes[8].tag = S("log_pile");
world->propTypes[8].scale=1; world->propTypes[8].scale=1;
world->propTypes[9].tag = S("nightstand"); world->propTypes[9].tag = S("nightstand");
world->propTypes[9].scale=1; world->propTypes[9].scale=1;
world->propTypes[10].tag = S("pool_table"); world->propTypes[10].tag = S("pool_table");
world->propTypes[10].scale=2; world->propTypes[10].scale=3;
world->propTypes[11].tag = S("saloon_ext"); world->propTypes[11].tag = S("saloon_ext");
world->propTypes[11].scale=6.875f; world->propTypes[11].scale=6.875f;
world->propTypes[12].tag = S("saloon_int"); world->propTypes[12].tag = S("saloon_int");
@@ -199,7 +206,7 @@ int main(int argc, char **argv)
world->propTypes[13].tag = S("house"); world->propTypes[13].tag = S("house");
world->propTypes[13].scale=6.875f; world->propTypes[13].scale=6.875f;
world->propTypes[14].tag = S("house_int"); world->propTypes[14].tag = S("house_int");
world->propTypes[14].scale=6.875f; world->propTypes[14].scale=12.875f;
world->propTypes[15].tag=S("tile_detail_0"); world->propTypes[15].tag=S("tile_detail_0");
world->propTypes[15].scale=1; world->propTypes[15].scale=1;
world->propTypes[16].tag = S("tile_detail_1"); world->propTypes[16].tag = S("tile_detail_1");
@@ -216,19 +223,15 @@ int main(int argc, char **argv)
world->propTypes[21].scale=1; world->propTypes[21].scale=1;
world->propCount = 0; world->propCount = 0;
world->props = M_ArenaPush(arena, World_Prop, .count=WORLD_PROP_MAX); world->props = M_ArenaPush(arena, World_Prop, .count=WORLD_PROP_MAX);
world->hitboxes = M_ArenaPush(arena, AABB, .count=WORLD_HITBOX_MAX); world->hitboxes = M_ArenaPush(arena, World_Hitbox, .count=WORLD_HITBOX_MAX);
world->portals = M_ArenaPush(arena, World_Portal, .count=64);
world->portalCount=0;
GenerateNavMesh(arena, world); GenerateNavMesh(arena, world);
} }
game->editor.enabled = false; game->editor.enabled = true;
game->editor.mode = G_EDITOR_MODE_TILE; game->editor.mode = G_EDITOR_MODE_TILE;
game->editor.currentLevel = WORLD_AREA_OUTSIDE; game->editor.currentLevel = WORLD_AREA_OUTSIDE;
game->editor.selectedNode = 0;
D_Animation animation;
{
U32 id = D_ImageHandle(&game->draw, S("npc_front_base_white"));
D_AnimationInit(&animation, id, 1, 4, 1.0f / 20.0f);
}
bool running = true; bool running = true;
@@ -244,6 +247,14 @@ int main(int argc, char **argv)
{ {
running = false; running = false;
} }
else if (e.type == SDL_EVENT_KEY_DOWN) {
Player *player = &game->world->player;
switch (e.key.key) {
case SDLK_R: { PlayerInit(game, player); } break;
case SDLK_F: {game->world->showPoster=!game->world->showPoster;}break;
}
}
V3f projection = G_CameraUnproject(&game->camera, V2f_Clip( V3f projection = G_CameraUnproject(&game->camera, V2f_Clip(
V2F(e.button.x, e.button.y), V2F(e.button.x, e.button.y),
V2F((F32) width, (F32) height) V2F((F32) width, (F32) height)
@@ -258,8 +269,8 @@ int main(int argc, char **argv)
if(e.type==SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) { if(e.type==SDL_EVENT_MOUSE_BUTTON_DOWN && e.button.button == SDL_BUTTON_LEFT) {
switch(game->editor.mode){ switch(game->editor.mode){
case G_EDITOR_MODE_TILE: { case G_EDITOR_MODE_TILE: {
F32 tilex = (S32)(game->editor.cursor.x+TILE_SIZE/2); F32 tilex = (F32) (S32)(game->editor.cursor.x+TILE_SIZE/2);
F32 tiley = (S32)(game->editor.cursor.y+TILE_SIZE/2); F32 tiley = (F32) (S32)(game->editor.cursor.y+TILE_SIZE/2);
game->world->map[(S32)tilex + (S32)tiley * 96] = game->editor.currentAsset; game->world->map[(S32)tilex + (S32)tiley * 96] = game->editor.currentAsset;
break; break;
} }
@@ -271,19 +282,33 @@ int main(int argc, char **argv)
break; break;
} }
case G_EDITOR_MODE_HITBOX: { case G_EDITOR_MODE_HITBOX: {
case G_EDITOR_MODE_PORTAL: {
game->editor.dragStart = game->editor.cursor; game->editor.dragStart = game->editor.cursor;
break; break;
} }
} }
} else if(e.type==SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT && game->editor.mode == G_EDITOR_MODE_HITBOX) { }} else if(e.type==SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT && game->editor.mode == G_EDITOR_MODE_HITBOX) {
// Add hitbox // Add hitbox
V2f topLeft = V2F(Min(game->editor.cursor.x, game->editor.dragStart.x), Min(game->editor.cursor.y, game->editor.dragStart.y)); V2f topLeft = V2F(Min(game->editor.cursor.x, game->editor.dragStart.x), Min(game->editor.cursor.y, game->editor.dragStart.y));
game->world->hitboxes[game->world->hitboxCount].pos = topLeft; game->world->hitboxes[game->world->hitboxCount].box.pos = topLeft;
game->world->hitboxes[game->world->hitboxCount].size = V2F( game->world->hitboxes[game->world->hitboxCount].box.size = V2F(
Abs(game->editor.cursor.x-game->editor.dragStart.x), Abs(game->editor.cursor.x-game->editor.dragStart.x),
Abs(game->editor.cursor.y-game->editor.dragStart.y) Abs(game->editor.cursor.y-game->editor.dragStart.y)
); );
game->world->hitboxes[game->world->hitboxCount].area = game->editor.currentAsset;
game->world->hitboxCount++; game->world->hitboxCount++;
GenerateNavMesh(game->arena, game->world);
} else if(e.type==SDL_EVENT_MOUSE_BUTTON_UP && e.button.button == SDL_BUTTON_LEFT && game->editor.mode == G_EDITOR_MODE_PORTAL) {
// Add portal
V2f topLeft = V2F(Min(game->editor.cursor.x, game->editor.dragStart.x), Min(game->editor.cursor.y, game->editor.dragStart.y));
game->world->portals[game->world->portalCount].box.pos = topLeft;
game->world->portals[game->world->portalCount].box.size = V2F(
Abs(game->editor.cursor.x-game->editor.dragStart.x),
Abs(game->editor.cursor.y-game->editor.dragStart.y)
);
game->world->portals[game->world->portalCount].area = game->editor.currentAsset;
game->world->portalCount++;
GenerateNavMesh(game->arena, game->world);
} }
} }
@@ -295,10 +320,12 @@ int main(int argc, char **argv)
} }
case SDLK_RIGHT: { case SDLK_RIGHT: {
game->editor.currentAsset = Min(game->editor.currentAsset+1, 64); game->editor.currentAsset = Min(game->editor.currentAsset+1, 64);
printf("editing with %d\n", game->editor.currentAsset);
break; break;
} }
case SDLK_LEFT: { case SDLK_LEFT: {
game->editor.currentAsset = Max(game->editor.currentAsset-1, 0); game->editor.currentAsset = Max(game->editor.currentAsset-1, 0);
printf("editing with %d\n", game->editor.currentAsset);
break; break;
} }
case SDLK_A: { case SDLK_A: {
@@ -327,6 +354,16 @@ int main(int argc, char **argv)
game->world->player.currentArea--; game->world->player.currentArea--;
break; break;
} }
case SDLK_E: {
game->editor.selectedNode++;
printf("selected %d\n", game->editor.selectedNode);
break;
}
case SDLK_Q: {
game->editor.selectedNode--;
printf("selected %d\n", game->editor.selectedNode);
break;
}
case SDLK_SPACE: { case SDLK_SPACE: {
game->editor.mode = (game->editor.mode + 1) % 4; game->editor.mode = (game->editor.mode + 1) % 4;
printf("EDITOR MODE %d\n", game->editor.mode); printf("EDITOR MODE %d\n", game->editor.mode);
@@ -336,6 +373,7 @@ int main(int argc, char **argv)
switch(game->editor.mode) { switch(game->editor.mode) {
case G_EDITOR_MODE_PROP: {game->world->propCount--;} case G_EDITOR_MODE_PROP: {game->world->propCount--;}
case G_EDITOR_MODE_HITBOX: {game->world->hitboxCount--;} case G_EDITOR_MODE_HITBOX: {game->world->hitboxCount--;}
case G_EDITOR_MODE_PORTAL: {game->world->portalCount--;}
} }
break; break;
} }
@@ -345,10 +383,10 @@ int main(int argc, char **argv)
if(!game->editor.enabled) { if(!game->editor.enabled) {
UpdateWorld(1.0f / 60.0f, game->world); UpdateWorld(1.0f / 60.0f, game->world);
game->camera.p.x = game->world->player.pos.x;
game->camera.p.y = game->world->player.pos.y; game->camera.p.x = game->world->player.collision.pos.x;
game->camera.p.y = game->world->player.collision.pos.y;
} }
D_AnimationUpdate(&animation, 1.0f / 250.0f);
int w, h; int w, h;
SDL_GetWindowSizeInPixels(window, &w, &h); SDL_GetWindowSizeInPixels(window, &w, &h);
@@ -387,14 +425,52 @@ int main(int argc, char **argv)
D_Begin(&game->draw, frame, D_MAX_RECTS); D_Begin(&game->draw, frame, D_MAX_RECTS);
RenderWorld(game->world, &game->draw); RenderWorld(game->world, &game->draw);
if(game->world->showPoster){
D_Rect(&game->draw, G_CameraBounds(&game->camera).min.x+4.8, G_CameraBounds(&game->camera).min.y+6.4, .texture=D_ImageHandle(&game->draw, S("poster")), .scale=12.0);
}
for(int i = 0; i < game->world->player.health; i++){
D_Rect(&game->draw, (G_CameraBounds(&game->camera).max.x-3)+i, G_CameraBounds(&game->camera).min.y+1.0, .texture=D_ImageHandle(&game->draw, S("heart")), .scale=1.0);
}
R2f aframe = D_AnimationFrame(&animation); //D_Text(&game->draw, game->draw.fonts, S("Small Test"), 0, 0);
D_Rect(&game->draw, 0, 0, .texture = animation.id, .uv = aframe, .flags = D_RECT_UV_ASPECT);
if(game->editor.enabled) { if(game->editor.enabled) {
G_Editor editor = game->editor; G_Editor editor = game->editor;
F32 tilex = floor(editor.cursor.x+TILE_SIZE/2); F32 tilex = cast(F32) floor(editor.cursor.x+TILE_SIZE/2);
F32 tiley = floor(editor.cursor.y+TILE_SIZE/2); F32 tiley = cast(F32) floor(editor.cursor.y+TILE_SIZE/2);
for (int i = 0; i < game->world->navMesh->nodeCount; i++) {
NavNode n = game->world->navMesh->nodes[i];
D_Rect(
&game->draw,
n.pos.x,
n.pos.y,
.texture = 0,
.scale = 0.2f,
);
}
for (int i = 0; i < game->world->navMesh->nodeCount; i++) {
NavNode n = game->world->navMesh->nodes[i];
if(i == editor.selectedNode) {
D_Rect(
&game->draw,
n.pos.x,
n.pos.y,
.texture = 0,
.scale = 0.2f,
.c = V4F(100, 255, 0, 100),
);
for(int j = 0; j < n.connectionCount; j++) {
D_Rect(
&game->draw,
game->world->navMesh->nodes[n.connections[j].NodeIndex].pos.x,
game->world->navMesh->nodes[n.connections[j].NodeIndex].pos.y,
.texture = 0,
.scale = 0.2f,
.c = V4F(0, 100, 0, 100),
);
}
}
}
switch(game->editor.mode) { switch(game->editor.mode) {
case G_EDITOR_MODE_TILE: { case G_EDITOR_MODE_TILE: {
World_Tile asset = game->world->tileTypes[editor.currentAsset]; World_Tile asset = game->world->tileTypes[editor.currentAsset];
@@ -407,21 +483,35 @@ int main(int argc, char **argv)
break; break;
} }
case G_EDITOR_MODE_HITBOX: { case G_EDITOR_MODE_HITBOX: {
for(int i = 0; i < game->world->hitboxCount; i++) { for(U32 i = 0; i < game->world->hitboxCount; i++) {
V2f centre = AABB_Centre(game->world->hitboxes[i]); if(game->world->player.currentArea == game->world->hitboxes[i].area) {
V2f centre = AABB_Centre(game->world->hitboxes[i].box);
D_Rect( D_Rect(
&game->draw, &game->draw,
centre.x, centre.x,
centre.y, centre.y,
.texture=0, .texture=0,
.dim=game->world->hitboxes[i].size, .dim=game->world->hitboxes[i].box.size,
.flags=D_RECT_IGNORE_ASPECT, .flags=D_RECT_IGNORE_ASPECT,
.c=V4F(100,0,0,0.7), .c=V4F(100,0,0,0.7f),
); );
} }
}
break; break;
} }
case G_EDITOR_MODE_POI: { case G_EDITOR_MODE_PORTAL: {
for(U32 i = 0; i < game->world->portalCount; i++) {
V2f centre = AABB_Centre(game->world->portals[i].box);
D_Rect(
&game->draw,
centre.x,
centre.y,
.texture=0,
.dim=game->world->portals[i].box.size,
.flags=D_RECT_IGNORE_ASPECT,
.c=V4F(0,0,100,0.7),
);
}
break; break;
} }
} }
+1
View File
@@ -14,5 +14,6 @@ function bool AABB_Collide(AABB a, AABB b);
function bool AABB_Point(AABB a, V2f v); function bool AABB_Point(AABB a, V2f v);
function bool AABB_Slab(V2f origin, V2f point, AABB a); function bool AABB_Slab(V2f origin, V2f point, AABB a);
function V2f AABB_Centre(AABB a); function V2f AABB_Centre(AABB a);
function bool AABB_Circle(F32 rad, V2f radOrigin, AABB a);
#endif // LD_GAME_AABB_H_ #endif // LD_GAME_AABB_H_
+14 -1
View File
@@ -1,12 +1,15 @@
#if !defined(LD_GAME_BANDIT_H_) #if !defined(LD_GAME_BANDIT_H_)
#define LD_GAME_BANDIT_H_ #define LD_GAME_BANDIT_H_
#include "outfit.h"
typedef enum BANDIT_ACTION BANDIT_ACTION; typedef enum BANDIT_ACTION BANDIT_ACTION;
enum BANDIT_ACTION { enum BANDIT_ACTION
{
BANDIT_WAITING, BANDIT_WAITING,
BANDIT_WALKING, BANDIT_WALKING,
BANDIT_RUNNING, BANDIT_RUNNING,
BANDIT_SHOOTING, BANDIT_SHOOTING,
BANDIT_SHOOTOUT,
}; };
typedef struct Bandit Bandit; typedef struct Bandit Bandit;
@@ -50,12 +53,22 @@ struct Bandit {
F32 shootDelay; F32 shootDelay;
// After each shot this is set to shootDelay; // After each shot this is set to shootDelay;
F32 shootCooldownTimer; F32 shootCooldownTimer;
// Countdown to shootout
F32 shootoutTimer;
// How long it takes them to reload. // How long it takes them to reload.
F32 reloadTime; F32 reloadTime;
// When gun is empty this is set to reloadTime.
F32 reloadTimer;
// Accuracy, their shots can vary between this angle either side (rads) // Accuracy, their shots can vary between this angle either side (rads)
F32 accuracyRange; F32 accuracyRange;
// A the circle around the bandit where they will trigger the quicktime reaction scene // A the circle around the bandit where they will trigger the quicktime reaction scene
F32 agroRadius; F32 agroRadius;
// What the bandit is wearing
G_Outfit outfit;
// What the bandit's outfit id's are
U32 *outfitChoices;
}; };
function V2f ShootTowards(Bandit* bandit, V2f target, Random* r);
function void BanditDraw(D_Context *draw, Bandit *bandit);
#endif // LD_GAME_BANDIT_H_ #endif // LD_GAME_BANDIT_H_
+47 -2
View File
@@ -1,6 +1,7 @@
#if !defined(LD_GAME_CORE_H_) #if !defined(LD_GAME_CORE_H_)
#define LD_GAME_CORE_H_ #define LD_GAME_CORE_H_
#include "world.h"
typedef struct World World;
typedef struct G_Camera G_Camera; typedef struct G_Camera G_Camera;
struct G_Camera { struct G_Camera {
@@ -20,7 +21,7 @@ enum G_EDITOR_MODE {
G_EDITOR_MODE_TILE, G_EDITOR_MODE_TILE,
G_EDITOR_MODE_PROP, G_EDITOR_MODE_PROP,
G_EDITOR_MODE_HITBOX, G_EDITOR_MODE_HITBOX,
G_EDITOR_MODE_POI, G_EDITOR_MODE_PORTAL,
}; };
typedef struct G_Editor G_Editor; typedef struct G_Editor G_Editor;
@@ -31,6 +32,7 @@ struct G_Editor {
G_EDITOR_MODE mode; G_EDITOR_MODE mode;
V2f cursor; V2f cursor;
V2f dragStart; V2f dragStart;
U32 selectedNode;
}; };
typedef struct G_State G_State; typedef struct G_State G_State;
@@ -44,6 +46,48 @@ struct G_State {
World *world; World *world;
}; };
typedef U32 G_OutfitDirection;
enum {
G_OUTFIT_DIR_FRONT = 0,
G_OUTFIT_DIR_SIDE,
G_OUTFIT_DIR_BACK,
G_OUTFIT_DIR_FLIPPED = (1 << 16)
};
typedef union G_OutfitSet G_OutfitSet;
union G_OutfitSet {
struct {
U32 base;
U32 eyes;
U32 face;
U32 hair;
U32 hat;
U32 shirt;
U32 shoes;
U32 trousers;
};
U32 e[8];
};
typedef struct G_Outfit G_Outfit;
struct G_Outfit {
D_Animation state; // .id in here isn't used for drawing
G_OutfitDirection dir;
union {
struct {
G_OutfitSet front;
G_OutfitSet side;
G_OutfitSet back;
};
G_OutfitSet e[3];
};
};
function void G_ImagesLoad(G_State *game); function void G_ImagesLoad(G_State *game);
function void G_PipelinesLoad(G_State *game); function void G_PipelinesLoad(G_State *game);
function void G_AudioLoad(G_State *game); function void G_AudioLoad(G_State *game);
@@ -56,6 +100,7 @@ function V3f G_CameraUnproject(G_Camera *camera, V2f clip);
function R3f G_CameraBounds(G_Camera *camera); function R3f G_CameraBounds(G_Camera *camera);
#include "world.h"
#include "aabb.h" #include "aabb.h"
#include "player.h" #include "player.h"
#include "nav.h" #include "nav.h"
+9 -1
View File
@@ -11,7 +11,7 @@ bool AABB_Collide(AABB a, AABB b)
bool AABB_Point(AABB a, V2f v) bool AABB_Point(AABB a, V2f v)
{ {
bool collision_x = a.pos.x + a.size.x >= v.x && a.pos.x <= v.x; bool collision_x = a.pos.x + a.size.x >= v.x && a.pos.x <= v.x;
bool collision_y = a.pos.x + a.size.y >= v.y && a.pos.y <= v.y; bool collision_y = a.pos.y + a.size.y >= v.y && a.pos.y <= v.y;
return collision_x && collision_y; return collision_x && collision_y;
} }
@@ -38,3 +38,11 @@ bool AABB_Slab(V2f origin, V2f point, AABB a)
V2f AABB_Centre(AABB a) { V2f AABB_Centre(AABB a) {
return V2F(a.pos.x + a.size.x/2, a.pos.y + a.size.y/2); return V2F(a.pos.x + a.size.x/2, a.pos.y + a.size.y/2);
} }
bool AABB_Circle(F32 rad, V2f radOrigin, AABB a)
{
V2f aCentre = AABB_Centre(a);
F32 xSq = (Abs(aCentre.x) - Abs(radOrigin.x)) * (Abs(aCentre.x) - Abs(radOrigin.x));
F32 ySq = (Abs(aCentre.y) - Abs(radOrigin.y)) * (Abs(aCentre.y) - Abs(radOrigin.y));
return SDL_sqrt(xSq + ySq) < rad;
}
+67 -2
View File
@@ -1,13 +1,32 @@
#include "game/world.h" #include "game/world.h"
#include "game/bandit.h" #include "game/bandit.h"
V2f ShootTowards(Bandit *bandit, V2f target, Random* r)
{
V2f shooterV2 = bandit->collision.pos;
F32 randX = Random_F32(r, -bandit->accuracyRange, bandit->accuracyRange);
F32 randY = Random_F32(r, -bandit->accuracyRange, bandit->accuracyRange);
return V2F(shooterV2.x + (target.x - shooterV2.x) * (1 + randX), shooterV2.x + (target.y - shooterV2.y) * (1 + randY));
}
void UpdateBandit(F32 delta, Bandit *bandit, World *world) { void UpdateBandit(F32 delta, Bandit *bandit, World *world) {
for(int i = 0; i < world->portalCount; i++) {
if(AABB_Collide(world->portals[0].box, bandit->collision)) {
bandit->currentArea = world->portals[0].area;
}
}
if ( if (
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, bandit->collision) && bandit->currentArea == world->player.currentArea) world->player.controls.shot && AABB_Slab(world->player.collision.pos, world->player.shotPos, bandit->collision) && bandit->currentArea == world->player.currentArea)
{ {
printf("You shot the bandit %*.s\n", Sv(bandit->name)); printf("You shot the bandit %*.s\n", Sv(bandit->name));
bandit->health--; bandit->health--;
} }
if (AABB_Circle(bandit->agroRadius, AABB_Centre(bandit->collision), world->player.collision) && !(bandit->mode == BANDIT_SHOOTING || bandit->mode == BANDIT_SHOOTOUT))
{
printf("begin shootout\n");
// shootout time o.o
bandit->mode = BANDIT_SHOOTOUT;
}
switch (bandit->mode) { switch (bandit->mode) {
case BANDIT_WAITING: case BANDIT_WAITING:
bandit->waitTime+=delta; bandit->waitTime+=delta;
@@ -41,7 +60,53 @@ void UpdateBandit(F32 delta, Bandit *bandit, World *world) {
bandit->collision.pos.x = cNav.pos.x * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.x * bandit->walkTimer/NPC_SPEED; bandit->collision.pos.x = cNav.pos.x * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.x * bandit->walkTimer/NPC_SPEED;
bandit->collision.pos.y = cNav.pos.y * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.y * bandit->walkTimer/NPC_SPEED; bandit->collision.pos.y = cNav.pos.y * (1 - bandit->walkTimer/NPC_SPEED) + tNav.pos.y * bandit->walkTimer/NPC_SPEED;
break; break;
// TODO Shooting case BANDIT_SHOOTOUT:
bandit->shootoutTimer-=delta;
if(bandit->shootoutTimer < 0){
bandit->mode=BANDIT_SHOOTING;
}
break;
case BANDIT_SHOOTING:
bandit->shootCooldownTimer -= delta;
bandit->reloadTimer -= delta;
if (bandit->shootCooldownTimer < 0 && bandit->reloadTimer < 0)
{
printf("\nshoot at player");
bandit->bullets--;
bandit->shootCooldownTimer = bandit->shootDelay;
V2f banditShot = ShootTowards(bandit, world->player.collision.pos, &world->random);
if(AABB_Slab(bandit->collision.pos, banditShot, world->player.collision)){
// gets shot lmao
printf("\nhit");
world->player.health--;
}
if(bandit->bullets == 0){
printf("\nenemy reload");
bandit->bullets = 6;
bandit->reloadTimer = bandit->reloadTime;
}
}
break;
// TODO Running away // TODO Running away
} }
} }
void BanditDraw(D_Context *draw, Bandit *bandit)
{
G_Outfit *outfit = &bandit->outfit;
R2f pframe = D_AnimationFrame(&outfit->state);
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it)
{
U32 flipped = (outfit->dir & G_OUTFIT_DIR_FLIPPED) != 0;
U32 dir = (outfit->dir & ~G_OUTFIT_DIR_FLIPPED);
U32 tid = outfit->e[dir].e[it];
if (tid != 0)
{
U32 flags = D_RECT_UV_ASPECT | (flipped ? D_RECT_FLIP_X : 0);
D_Rect(draw, bandit->collision.pos.x, bandit->collision.pos.y, .texture = tid, .uv = pframe, .flags = flags);
}
}
}
+25
View File
@@ -4,6 +4,11 @@
#include "core/math.h" #include "core/math.h"
void UpdateNPC(F32 delta, NPC *npc, World *world) { void UpdateNPC(F32 delta, NPC *npc, World *world) {
for(int i = 0; i < world->portalCount; i++) {
if(AABB_Collide(world->portals[0].box, npc->collision)) {
npc->currentArea = world->portals[0].area;
}
}
switch (npc->mode) { switch (npc->mode) {
case NPC_ACTION_WAITING: case NPC_ACTION_WAITING:
npc->waitTime+=delta; npc->waitTime+=delta;
@@ -41,3 +46,23 @@ void UpdateNPC(F32 delta, NPC *npc, World *world) {
break; break;
} }
} }
void NPCDraw(D_Context *draw, NPC *npc)
{
G_Outfit *outfit = &npc->outfit;
R2f pframe = D_AnimationFrame(&outfit->state);
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it)
{
U32 flipped = (outfit->dir & G_OUTFIT_DIR_FLIPPED) != 0;
U32 dir = (outfit->dir & ~G_OUTFIT_DIR_FLIPPED);
U32 tid = outfit->e[dir].e[it];
if (tid != 0)
{
U32 flags = D_RECT_UV_ASPECT | (flipped ? D_RECT_FLIP_X : 0);
D_Rect(draw, npc->collision.pos.x, npc->collision.pos.y, .texture = tid, .uv = pframe, .flags = flags);
}
}
}
+31
View File
@@ -0,0 +1,31 @@
U32* GenOutfit(G_Outfit *o, World *world, G_State *game)
{
U32 *outfitChoices = M_ArenaPush(world->arena, U32, .count = 8);
G_Outfit *outfit = o;
D_AnimationInit(&outfit->state, 0, 1, 4, 1.0f / 6.0f);
M_TempScope(0, 0)
{
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it)
{
U32 idx = Random_Next(&world->random) % __outfit_counts[it];
// We just allow face, hair and hat to default to 0 meaning the player doesn't have one
if (idx != 0 || it < 2 || it > 4)
{
outfit->front.e[it] = OUTFIT_IMG(front, idx);
outfit->side.e[it] = OUTFIT_IMG(side, idx);
if ((idx + 1) <= __outfit_counts[it])
{
outfit->back.e[it] = OUTFIT_IMG(back, idx);
}
}
outfitChoices[it] = idx;
}
}
return outfitChoices;
}
+86 -2
View File
@@ -2,6 +2,42 @@
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include <SDL3/SDL_keycode.h> #include <SDL3/SDL_keycode.h>
#include <stdio.h> #include <stdio.h>
#include "../outfit.h"
#include "../npc.h"
void PlayerInit(G_State *game, Player *player) {
World *world = game->world;
player->world = world;
player->bulletsLoaded = PLAYER_BULLET_COUNT;
player->currentArea = WORLD_AREA_OUTSIDE;
player->health = 3;
player->collision.size.x = 1;
player->collision.size.x = 2;
G_Outfit *outfit = &player->outfit;
D_AnimationInit(&outfit->state, 0, 1, 4, 1.0f / 6.0f);
M_TempScope(0, 0) {
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it) {
U32 idx = Random_Next(&world->random) % __outfit_counts[it];
// We just allow face, hair and hat to default to 0 meaning the player doesn't have one
if (idx != 0 || it < 2 || it > 4) {
outfit->front.e[it] = OUTFIT_IMG(front, idx);
outfit->side.e[it] = OUTFIT_IMG(side, idx);
if ((idx + 1) <= __outfit_counts[it]) {
outfit->back.e[it] = OUTFIT_IMG(back, idx);
}
}
}
}
}
void PlayerInput(SDL_Event *event, Player *player) void PlayerInput(SDL_Event *event, Player *player)
{ {
@@ -31,6 +67,16 @@ void PlayerInput(SDL_Event *event, Player *player)
player->controls.downDown = val; player->controls.downDown = val;
break; break;
} }
case SDLK_E:
{
for(int i = 0; player->world->npcCount; i++){
NPC *npc = &player->world->npcs[i];
if(AABB_Circle(npc->interationRadius, npc->collision.pos, player->collision) && !npc->infoGiven){
npc->infoGiven=true;
player->knownDetails[player->detailCount] = player->world->bandit.outfitChoices[player->detailCount];
}
}
}
} }
} }
if ( if (
@@ -53,18 +99,34 @@ void PlayerInput(SDL_Event *event, Player *player)
void PlayerUpdate(F32 delta, Player *player) { void PlayerUpdate(F32 delta, Player *player) {
player->controls.shot = false; player->controls.shot = false;
V2f dir = V2F(0, 0); V2f dir = V2F(0, 0);
if(player->health == 0){
printf("dead :(");
player->health = 3;
}
if(player->controls.upDown) { if(player->controls.upDown) {
dir.y -= 1; dir.y -= 1;
player->outfit.dir = G_OUTFIT_DIR_BACK;
} }
if(player->controls.downDown) { if(player->controls.downDown) {
dir.y += 1; dir.y += 1;
player->outfit.dir = G_OUTFIT_DIR_FRONT;
} }
if(player->controls.leftDown) { if(player->controls.leftDown) {
dir.x -= 1; dir.x -= 1;
player->outfit.dir = G_OUTFIT_DIR_SIDE | G_OUTFIT_DIR_FLIPPED;
} }
if(player->controls.rightDown) { if(player->controls.rightDown) {
dir.x += 1; dir.x += 1;
player->outfit.dir = G_OUTFIT_DIR_SIDE;
} }
if (dir.x != 0 || dir.y != 0) {
D_AnimationUpdate(&player->outfit.state, delta);
}
else {
player->outfit.state.index = 0;
}
if(player->reloadTimer > 0) { if(player->reloadTimer > 0) {
player->reloadTimer-=delta; player->reloadTimer-=delta;
if(player->reloadTimer <= 0) { if(player->reloadTimer <= 0) {
@@ -73,6 +135,28 @@ void PlayerUpdate(F32 delta, Player *player) {
} }
} }
dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta); dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta);
player->pos.x += dir.x; player->collision.pos.x += dir.x;
player->pos.y += dir.y; player->collision.pos.y += dir.y;
for(int i = 0; i < player->world->portalCount; i++) {
if(AABB_Collide(player->world->portals[0].box, player->collision)) {
player->currentArea = player->world->portals[0].area;
}
}
}
void PlayerDraw(D_Context *draw, Player *player) {
G_Outfit *outfit = &player->outfit;
R2f pframe = D_AnimationFrame(&outfit->state);
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it) {
U32 flipped = (outfit->dir & G_OUTFIT_DIR_FLIPPED) != 0;
U32 dir = (outfit->dir & ~G_OUTFIT_DIR_FLIPPED);
U32 tid = outfit->e[dir].e[it];
if (tid != 0) {
U32 flags = D_RECT_UV_ASPECT | (flipped ? D_RECT_FLIP_X : 0);
D_Rect(draw, player->collision.pos.x, player->collision.pos.y, .texture = tid, .uv = pframe, .flags = flags);
}
}
} }
+184 -90
View File
@@ -9,6 +9,9 @@
void UpdateWorld(F32 delta, World *world) void UpdateWorld(F32 delta, World *world)
{ {
if(world->bandit.mode == BANDIT_SHOOTOUT){
delta = delta/4;
}
UpdateBandit(delta, &world->bandit, world); UpdateBandit(delta, &world->bandit, world);
UpdateNPCs(delta, world); UpdateNPCs(delta, world);
PlayerUpdate(delta, &world->player); PlayerUpdate(delta, &world->player);
@@ -21,7 +24,7 @@ void UpdateNPCs(F32 delta, World *world)
NPC *npc = &world->npcs[i]; NPC *npc = &world->npcs[i];
UpdateNPC(delta, npc, world); UpdateNPC(delta, npc, world);
if ( if (
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea) world->player.controls.shot && AABB_Slab(world->player.collision.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea)
{ {
printf("You shot %*.s\n", Sv(world->npcs[i].name)); printf("You shot %*.s\n", Sv(world->npcs[i].name));
} }
@@ -32,7 +35,7 @@ void ProcessEvents(SDL_Event *event, World *world)
{ {
PlayerInput(event, &world->player); PlayerInput(event, &world->player);
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){ if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){
SaveWorld(world->arena, world); SaveWorld(world);
} }
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F6){ if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F6){
LoadWorld(world->arena, world); LoadWorld(world->arena, world);
@@ -50,7 +53,7 @@ void RenderWorld(World *world, D_Context *draw) {
); );
} }
} }
for (int i = 0; i < world->propCount; i++) { for (U32 i = 0; i < world->propCount; i++) {
if(world->props[i].area == world->player.currentArea) { if(world->props[i].area == world->player.currentArea) {
D_Rect( D_Rect(
draw, draw,
@@ -61,119 +64,170 @@ void RenderWorld(World *world, D_Context *draw) {
); );
} }
} }
for (int i = 0; i < world->navMesh->nodeCount; i++) {
NavNode n = world->navMesh->nodes[i];
D_Rect(
draw,
n.pos.x,
n.pos.y,
.texture = 0,
.scale = 0.2f,
);
}
for(U32 i = 0; i < world->npcCount; i++) { for(U32 i = 0; i < world->npcCount; i++) {
NPC npc = world->npcs[i]; NPC npc = world->npcs[i];
if(npc.currentArea == world->player.currentArea) { if(npc.currentArea == world->player.currentArea) {
V2f drawPos = AABB_Centre(npc.collision); NPCDraw(draw, &world->npcs[i]);
D_Rect(draw, drawPos.x, drawPos.y, .texture = 1);
} }
} }
if(world->bandit.currentArea == world->player.currentArea) {
V2f drawPos = AABB_Centre(world->bandit.collision);
D_Rect(draw, drawPos.x, drawPos.y, .texture = 9);
}
D_Rect(draw, world->player.pos.x, world->player.pos.y, .texture = 1);
}
void SaveWorld(M_Arena *arena, World *world) { BanditDraw(draw, &world->bandit);
printf("Saving world\n"); PlayerDraw(draw, &world->player);
}
#define WRITE(v) FS_FileWrite(file, &(v), sizeof(v), offset); offset += sizeof(v)
#define WRITEN(v, n) FS_FileWrite(file, v, (n) * sizeof(*(v)), offset); offset += ((n) * sizeof(*(v)))
void SaveWorld(World *world) {
printf("--- Saving World ---\n");
printf(" - %d props\n", world->propCount);
printf(" - %d hitboxes\n", world->hitboxCount);
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE); OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE);
U32 offset = 0; U64 offset = 0;
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
FS_FileWrite(file, &world->tileTypes[i].tag.count, sizeof(S64), offset); for (U32 i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
offset += sizeof(S64); World_Tile *tile = &world->tileTypes[i];
FS_FileWrite(file, world->tileTypes[i].tag.data, world->tileTypes[i].tag.count, offset);
offset += sizeof(U8) * world->tileTypes[i].tag.count; WRITE(tile->tag.count);
FS_FileWrite(file, &world->tileTypes[i].rotation, sizeof(F32), offset); WRITEN(tile->tag.data, tile->tag.count);
offset += sizeof(F32); WRITE(tile->rotation);
}
for(int i = 0; i < WORLD_PROP_TYPE_MAX; i++) {
FS_FileWrite(file, &world->propTypes[i].tag.count, sizeof(S64), offset);
offset += sizeof(S64);
FS_FileWrite(file, world->propTypes[i].tag.data, world->propTypes[i].tag.count, offset);
offset += sizeof(U8) * world->propTypes[i].tag.count;
FS_FileWrite(file, &world->propTypes[i].scale, sizeof(F32), offset);
offset += sizeof(F32);
} }
FS_FileWrite(file, world->propTypes, sizeof(World_PropType)*WORLD_PROP_TYPE_MAX, offset); for (U32 i = 0; i < WORLD_PROP_TYPE_MAX; i++) {
offset += sizeof(World_PropType)*WORLD_PROP_TYPE_MAX; World_PropType *type = &world->propTypes[i];
FS_FileWrite(file, &world->propCount, sizeof(U32), offset); WRITE(type->tag.count);
offset += sizeof(U32); WRITEN(type->tag.data, type->tag.count);
WRITE(type->scale);
}
FS_FileWrite(file, world->props, sizeof(World_Prop)*WORLD_PROP_MAX, offset); WRITE(world->propCount);
offset += sizeof(World_Prop)*WORLD_PROP_MAX; WRITEN(world->props, WORLD_PROP_MAX);
FS_FileWrite(file, &world->hitboxCount, sizeof(U32), offset); WRITE(world->hitboxCount);
offset += sizeof(U32); WRITEN(world->hitboxes, WORLD_HITBOX_MAX);
FS_FileWrite(file, world->hitboxes, sizeof(AABB)*WORLD_HITBOX_MAX, offset); WRITEN(world->map, WORLD_MAP_MAX);
offset += sizeof(AABB)*WORLD_HITBOX_MAX;
FS_FileWrite(file, world->map, sizeof(U32)*WORLD_MAP_MAX, offset);
offset += sizeof(U32)*WORLD_MAP_MAX;
WRITE(world->portalCount);
WRITEN(world->portals, WORLD_PORTAL_MAX);
FS_FileClose(file); FS_FileClose(file);
printf("Saved world :)\n");
printf("--- World Saved ---\n");
} }
void LoadWorld(M_Arena *arena, World *world) { void LoadWorld(M_Arena *arena, World *world) {
printf("loading world\n"); printf("--- Loading World ---\n");
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_READ);
U32 offset = 0;
M_TempScope(0, 0) {
Str8 data = FS_ReadEntireFile(temp.arena, S("world.sgdat"));
U8 *base = data.data;
// Load tile types
//
world->tileTypes = M_ArenaPush(arena, World_Tile, .count = WORLD_TILE_TYPE_MAX); world->tileTypes = M_ArenaPush(arena, World_Tile, .count = WORLD_TILE_TYPE_MAX);
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) { for (U32 it = 0; it < WORLD_TILE_TYPE_MAX; ++it) {
FS_FileRead(file, &world->tileTypes[i].tag.count, sizeof(S64), offset); World_Tile *type = &world->tileTypes[it];
offset += sizeof(S64);
world->tileTypes[i].tag.data = M_ArenaPush(arena, U8, .count=world->tileTypes[i].tag.count); Str8 name;
FS_FileRead(file, world->tileTypes[i].tag.data, world->tileTypes[i].tag.count, offset); name.count = *(S64 *) base;
offset += sizeof(U8) * world->tileTypes[i].tag.count; name.data = base + 8;
FS_FileRead(file, &world->tileTypes[i].rotation, sizeof(F32), offset);
offset += sizeof(F32); base += 8;
base += name.count;
if (name.count != 0) {
// Means we likely got a vaild tag
type->tag = Str8_Copy(arena, name);
type->rotation = *(F32 *) base;
} }
base += 4;
}
// Load prop types
//
world->propTypes = M_ArenaPush(arena, World_PropType, .count = WORLD_PROP_TYPE_MAX); world->propTypes = M_ArenaPush(arena, World_PropType, .count = WORLD_PROP_TYPE_MAX);
for(int i = 0; i < WORLD_PROP_TYPE_MAX; i++) { for (U32 it = 0; it < WORLD_PROP_TYPE_MAX; ++it) {
FS_FileRead(file, &world->propTypes[i].tag.count, sizeof(S64), offset); World_PropType *type = &world->propTypes[it];
offset += sizeof(S64);
world->propTypes[i].tag.data = M_ArenaPush(arena, U8, .count=world->propTypes[i].tag.count); Str8 name;
FS_FileRead(file, world->propTypes[i].tag.data, world->propTypes[i].tag.count, offset); name.count = *(S64 *) base;
offset += sizeof(U8) * world->propTypes[i].tag.count; name.data = base + 8;
FS_FileRead(file, &world->propTypes[i].scale, sizeof(F32), offset);
offset += sizeof(F32); base += 8;
base += name.count;
if (name.count != 0) {
type->tag = Str8_Copy(arena, name);
type->scale = *(F32 *) base;
} }
FS_FileRead(file, &world->propCount, sizeof(U32), offset); base += 4;
offset += sizeof(U32); }
// Prop locations
{
U32 n_props = *(U32 *) base; base += 4;
World_Prop *props = (World_Prop *) base;
world->propCount = n_props;
world->props = M_ArenaPush(arena, World_Prop, .count = WORLD_PROP_MAX); world->props = M_ArenaPush(arena, World_Prop, .count = WORLD_PROP_MAX);
FS_FileRead(file, world->props, sizeof(World_Prop)*WORLD_PROP_MAX, offset);
offset += sizeof(World_Prop)*world->propCount;
FS_FileRead(file, &world->hitboxCount, sizeof(U32), offset); M_CopySize(world->props, props, n_props * sizeof(World_Prop));
offset += sizeof(U32);
world->hitboxes = M_ArenaPush(arena, AABB, .count=WORLD_HITBOX_MAX); base += (WORLD_PROP_MAX * sizeof(World_Prop));
FS_FileRead(file, world->hitboxes, sizeof(AABB)*WORLD_HITBOX_MAX, offset); }
offset += sizeof(AABB)*world->hitboxCount;
// Hitboxes
//
{
U32 n_hitbox = *(U32 *) base; base += 4;
World_Hitbox *boxes = (World_Hitbox *) base;
world->hitboxCount = n_hitbox;
world->hitboxes = M_ArenaPush(arena, World_Hitbox, .count = WORLD_HITBOX_MAX);
M_CopySize(world->hitboxes, boxes, n_hitbox * sizeof(World_Hitbox));
base += (WORLD_HITBOX_MAX * sizeof(World_Hitbox));
}
// Map
//
{
U32 *__map = (U32 *) base;
world->map = M_ArenaPush(arena, U32, .count = WORLD_MAP_MAX); world->map = M_ArenaPush(arena, U32, .count = WORLD_MAP_MAX);
FS_FileRead(file, world->map, sizeof(U32)*WORLD_MAP_MAX, offset); M_CopySize(world->map, __map, WORLD_MAP_MAX * sizeof(U32));
offset += sizeof(U32)*WORLD_MAP_MAX;
base += (WORLD_MAP_MAX * sizeof(U32));
}
{
U32 n_portals = *(U32 *) base; base += 4;
World_Portal *portals = (World_Portal *) base;
world->portalCount = n_portals;
world->portals = M_ArenaPush(arena, World_Portal, .count = WORLD_PORTAL_MAX);
M_CopySize(world->portals, portals, n_portals * sizeof(World_Portal));
base += (WORLD_PORTAL_MAX * sizeof(World_Portal));
}
if (base != (data.data + data.count)) {
printf("--- OFFSET MISMATCH ---\n");
}
FS_FileClose(file);
printf("loaded world\n"); printf("loaded world\n");
printf(" - %d props\n", world->propCount);
printf(" - %d hitboxes\n", world->hitboxCount);
printf("--- Loaded World ---\n");
}
} }
void GenerateNavMesh(M_Arena *arena, World *world) { void GenerateNavMesh(M_Arena *arena, World *world) {
@@ -182,29 +236,69 @@ void GenerateNavMesh(M_Arena *arena, World *world) {
for(int i = 0; i < WORLD_MAP_MAX; i++) { for(int i = 0; i < WORLD_MAP_MAX; i++) {
U32 x = (i % 96); U32 x = (i % 96);
U32 y = (i / 96); U32 y = (i / 96);
bool skip = false;
for(U32 hi = 0; hi < world->hitboxCount; hi++) {
if(AABB_Point(world->hitboxes[hi].box, V2F((F32) x, (F32) y))) {
skip = true;
break;
}
}
if(skip) {continue;}
world->navMesh->nodes[world->navMesh->nodeCount].pos.x = x; world->navMesh->nodes[world->navMesh->nodeCount].pos.x = x;
world->navMesh->nodes[world->navMesh->nodeCount].pos.y = y; world->navMesh->nodes[world->navMesh->nodeCount].pos.y = y;
U32 cost = 20;
if(Str8_Equal(world->tileTypes[world->map[i]].tag, S("path_middle"), STR8_EQUAL_IGNORE_CASE)) {
cost = 10;
}
world->navMesh->nodes[world->navMesh->nodeCount].connectionCount = 0; world->navMesh->nodes[world->navMesh->nodeCount].connectionCount = 0;
for(int nx = -1; nx < 2; nx++){ for(int nx = -1; nx < 2; nx++){
for(int ny = -1; ny < 2; ny++){ for(int ny = -1; ny < 2; ny++){
if((nx==ny) && nx==0) {continue;} if(nx==0 && ny==0) {continue;}
if(x+nx < 0 || x+nx > 95) { if(x+nx < 0 || x+nx > 95) {
continue; continue;
} }
if(y+ny < 0 || y+ny > 49) { if(y+ny < 0 || y+ny > 49) {
continue; continue;
} }
U32 index = x+nx + (y+ny)*96; // It's quad for loop time :D
for(U32 hi = 0; hi < world->hitboxCount; hi++) {
if(AABB_Point(world->hitboxes[hi].box, V2F((F32) (x + nx), (F32) (y + ny)))) {
skip = true;
break;
}
}
U32 nCount = world->navMesh->nodeCount; U32 nCount = world->navMesh->nodeCount;
S32 index = -1;
for(int ohgod = 0; ohgod < nCount; ohgod++) {
if(world->navMesh->nodes[ohgod].pos.x == nx+x&& world->navMesh->nodes[ohgod].pos.y == y+ny) {
index=ohgod;
break;
}
}
F32 cost = 20;
if(ny+nx == 2) {
cost = 40;
};
if(Str8_Equal(world->tileTypes[world->map[i]].tag, S("path_middle"), STR8_EQUAL_IGNORE_CASE)) {
cost = 1;
if(Abs(ny+nx) == 2) {
cost = 4;
};
}
if(index < 0) {continue;}
skip |= index > nCount;
if(skip) {continue;}
world->navMesh->nodes[nCount].connections[world->navMesh->nodes[nCount].connectionCount].NodeIndex = index; world->navMesh->nodes[nCount].connections[world->navMesh->nodes[nCount].connectionCount].NodeIndex = index;
world->navMesh->nodes[nCount].connections[world->navMesh->nodes[nCount].connectionCount].Cost = cost; world->navMesh->nodes[nCount].connections[world->navMesh->nodes[nCount].connectionCount].Cost = cost;
world->navMesh->nodes[index].connections[world->navMesh->nodes[index].connectionCount].NodeIndex = nCount;
world->navMesh->nodes[index].connections[world->navMesh->nodes[index].connectionCount].Cost = cost;
world->navMesh->nodes[nCount].connectionCount++; world->navMesh->nodes[nCount].connectionCount++;
world->navMesh->nodes[index].connectionCount++;
} }
} }
world->navMesh->nodeCount++; world->navMesh->nodeCount++;
} }
for(int i = 0; i < world->npcCount; i++) {
world->npcs[i].mode = NPC_ACTION_WAITING;
world->npcs[i].maxWaitTime = Random_F32(&world->random, 20, 140);
world->npcs[i].waitTime = 0;
world->npcs[i].currentNavNode=0;
world->npcs[i].pathIndex = 0;
}
} }
+7 -2
View File
@@ -46,10 +46,15 @@ struct NPC {
U32 targetNavNode; U32 targetNavNode;
// How long the npc has been walking to the next index // How long the npc has been walking to the next index
F32 walkTimer; F32 walkTimer;
// Space within you can interact with the NPC.
F32 interationRadius;
//// Knowledge //// Knowledge
// What the NPC knows about the bandit. // What the NPC knows about the bandit.
NPC_LOOK banditKnowledge; NPC_LOOK banditKnowledge;
// NPC clothes
G_Outfit outfit;
// if the NPC has given info
bool infoGiven;
}; };
function void NPCDraw(D_Context *draw, NPC *npc);
#endif // LD_GAME_NPC_H_ #endif // LD_GAME_NPC_H_
+45
View File
@@ -0,0 +1,45 @@
#if !defined(LD_GAME_OUTFIT_H)
#define LD_GAME_OUTFIT_H
#define G_OUTFIT_COMPONENT_COUNT 8
global_var Str8 __outfit_names[] = {
Sl("npc_%s_base_%d"),
Sl("npc_%s_eyes_%d"),
Sl("npc_%s_face_%d"),
Sl("npc_%s_hair_%d"),
Sl("npc_%s_hat_%d"),
Sl("npc_%s_shirt_%d"),
Sl("npc_%s_shoes_%d"),
Sl("npc_%s_trousers_%d")};
global_var U32 __outfit_counts[] = {
2, // base
3, // eyes
5, // face
4, // hair
3, // hat
2, // shirt
1, // shoes
2 // trousers
};
global_var U32 __outfit_back_counts[] = {
2, // base
0, // eyes
3, // face
4, // hair
3, // hat
2, // shirt
1, // shoes
2 // trousers
};
StaticAssert(ArraySize(__outfit_names) == ArraySize(__outfit_counts));
#define OUTFIT_IMG(dir, n) D_ImageHandle(&game->draw, Sf(temp.arena, (const char *)__outfit_names[it].data, #dir, n))
function U32* GenOutfit(G_Outfit *o, World *world, G_State *game);
#endif // LD_GAME_OUTFIT_H
+11 -1
View File
@@ -5,6 +5,7 @@
#include "../core/macros.h" #include "../core/macros.h"
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include "aabb.h"
#define PLAYER_SPEED 10.0f #define PLAYER_SPEED 10.0f
#define PLAYER_RELOAD_TIME 1.5f #define PLAYER_RELOAD_TIME 1.5f
@@ -23,15 +24,24 @@ typedef struct Player Player;
struct Player struct Player
{ {
World *world; World *world;
V2f pos; AABB collision;
World_Area currentArea; World_Area currentArea;
U32 bulletsLoaded; U32 bulletsLoaded;
ControlState controls; ControlState controls;
V2f shotPos; V2f shotPos;
G_Outfit outfit;
U32 health;
F32 reloadTimer; F32 reloadTimer;
U32 *knownDetails;
U32 detailCount;
}; };
function void PlayerInit(G_State *game, Player *player);
function void PlayerDraw(D_Context *draw, Player *player);
function void PlayerInput(SDL_Event *event, Player *player); function void PlayerInput(SDL_Event *event, Player *player);
function void PlayerUpdate(F32 delta, Player *player); function void PlayerUpdate(F32 delta, Player *player);
+19 -5
View File
@@ -2,19 +2,21 @@
#define LD_GAME_WORLD_H_ #define LD_GAME_WORLD_H_
#include "../core/math.h" #include "../core/math.h"
#include "./aabb.h"
#define WORLD_HITBOX_MAX 4096 #define WORLD_HITBOX_MAX 4096
#define WORLD_PROP_MAX 2048 #define WORLD_PROP_MAX 2048
#define WORLD_PROP_TYPE_MAX 64 #define WORLD_PROP_TYPE_MAX 64
#define WORLD_TILE_TYPE_MAX 64 #define WORLD_TILE_TYPE_MAX 64
#define WORLD_MAP_MAX 4800 #define WORLD_MAP_MAX 4800
#define WORLD_PORTAL_MAX 64
// Areas are which // Areas are which
typedef U32 World_Area; typedef U32 World_Area;
enum World_Area enum World_Area
{ {
WORLD_AREA_OUTSIDE = (1 << 0), WORLD_AREA_OUTSIDE = 1,
WORLD_AREA_SALOON = (1 << 1), WORLD_AREA_SALOON = 2,
}; };
typedef struct World_Tile World_Tile; typedef struct World_Tile World_Tile;
@@ -37,6 +39,15 @@ struct World_Prop
V2f pos; V2f pos;
}; };
typedef struct World_Portal World_Portal;
struct World_Portal
{
AABB box;
World_Area area;
};
typedef World_Portal World_Hitbox;
typedef struct World World; typedef struct World World;
#include "player.h" #include "player.h"
#include "npc.h" #include "npc.h"
@@ -53,12 +64,15 @@ struct World {
World_Tile *tileTypes; World_Tile *tileTypes;
World_PropType *propTypes; World_PropType *propTypes;
World_Prop *props; World_Prop *props;
AABB *hitboxes; World_Hitbox *hitboxes;
World_Portal *portals;
U32 *map; U32 *map;
bool showPoster;
U32 propCount; U32 propCount;
U32 portalCount;
U32 hitboxCount; U32 hitboxCount;
//// Player //// Player
Player player; Player player;
@@ -82,7 +96,7 @@ function void UpdateNPC(F32 delta, NPC *npc, World *world);
function void UpdateBandit(F32 delta, Bandit *bandit, World *world); function void UpdateBandit(F32 delta, Bandit *bandit, World *world);
function void LoadWorld(M_Arena *arena, World *world); function void LoadWorld(M_Arena *arena, World *world);
function void SaveWorld(M_Arena *arena, World *world); function void SaveWorld(World *world);
function void GenerateNavMesh(M_Arena *arena, World *world); function void GenerateNavMesh(M_Arena *arena, World *world);
#endif // LD_GAME_WORLD_H_ #endif // LD_GAME_WORLD_H_
BIN
View File
Binary file not shown.