From 7f77d7ad5281a851a84fef41e27a50fa1fcb3987 Mon Sep 17 00:00:00 2001 From: declan Date: Mon, 6 Oct 2025 23:08:15 +0100 Subject: [PATCH 1/3] npc and bandit dressup, bits of UI added, WIP NPC interaction --- assets/heart.png | Bin 0 -> 289 bytes assets/poster.png | Bin 0 -> 14563 bytes code/first.c | 15 ++++++++++-- code/game/bandit.h | 9 +++++-- code/game/impl/bandit.c | 30 +++++++++++++++++++---- code/game/impl/npc.c | 20 ++++++++++++++++ code/game/impl/outfit.c | 31 ++++++++++++++++++++++++ code/game/impl/player.c | 52 ++++++++++------------------------------ code/game/impl/world.c | 8 ++----- code/game/npc.h | 9 +++++-- code/game/outfit.h | 45 ++++++++++++++++++++++++++++++++++ code/game/player.h | 3 +++ code/game/world.h | 2 +- 13 files changed, 166 insertions(+), 58 deletions(-) create mode 100644 assets/heart.png create mode 100644 assets/poster.png create mode 100644 code/game/impl/outfit.c create mode 100644 code/game/outfit.h diff --git a/assets/heart.png b/assets/heart.png new file mode 100644 index 0000000000000000000000000000000000000000..8e03d251cf6c616349cf11f7562a58e53a8fdaff GIT binary patch literal 289 zcmV++0p9+JP)Px#+et)0R5*>rlD!RsFcgFjWKpLw?@<#(a4x4_wO<)i3}6+RwW4 zs;={1p|zh#a5!%oJjc-w!6$ky3vvJ?1YisbtpOtIe<5!g0KhC|bhBnDfr#e|?tLEx zkMy%iM^eV%wXS$%878F?e;j8@LKv}ouvHR+;f^s3Zox4n;X+MhZ$XKJ!>>mRTuGrd nE@`?8Zx-;9J@`=WD(_|9y!U~WY=q()00000NkvXXu0mjfW2<$| literal 0 HcmV?d00001 diff --git a/assets/poster.png b/assets/poster.png new file mode 100644 index 0000000000000000000000000000000000000000..8cc415a41339226b515923abb089170cfd405864 GIT binary patch literal 14563 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 literal 0 HcmV?d00001 diff --git a/code/first.c b/code/first.c index 6f2762c..1e48fa1 100644 --- a/code/first.c +++ b/code/first.c @@ -24,6 +24,7 @@ #include "game/impl/world.c" #include "game/impl/npc.c" #include "game/impl/bandit.c" +#include "game/impl/outfit.c" int main(int argc, char **argv) { @@ -101,7 +102,7 @@ int main(int argc, char **argv) game->world = world; world->arena = arena; world->random = Random_Seed(29237489723847); - world->npcCount = 127; + world->npcCount = 12; for(U32 i = 0; i < world->npcCount; i++) { NPC *npc1 = &world->npcs[i]; npc1->collision.pos.x = 0; @@ -114,6 +115,7 @@ int main(int argc, char **argv) npc1->waitTime = 0; npc1->maxWaitTime = 1; npc1->currentNavNode = 0; + GenOutfit(&npc1->outfit,world,game); } Bandit *badman = &world->bandit; @@ -127,7 +129,7 @@ int main(int argc, char **argv) badman->maxWaitTime = 2; badman->poiCount = 2; badman->shootoutTimer = 1.5; - badman->agroRadius = 600.0; + badman->agroRadius = 6.0; badman->bullets = 6; badman->shootDelay = 1; badman->accuracyRange = 0.25; @@ -135,6 +137,8 @@ int main(int argc, char **argv) badman->reloadTimer = 0; badman->pointsOfInterest[0] = 937; badman->pointsOfInterest[1] = 12; + badman->outfitChoices = GenOutfit(&badman->outfit, world, game); + badman->currentArea = WORLD_AREA_OUTSIDE; world->npcPOI[0] = 100; @@ -247,6 +251,7 @@ int main(int argc, char **argv) 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; } } @@ -420,6 +425,12 @@ int main(int argc, char **argv) D_Begin(&game->draw, frame, D_MAX_RECTS); 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); + } //D_Text(&game->draw, game->draw.fonts, S("Small Test"), 0, 0); diff --git a/code/game/bandit.h b/code/game/bandit.h index b9eb7f8..0aceecf 100644 --- a/code/game/bandit.h +++ b/code/game/bandit.h @@ -1,5 +1,6 @@ #if !defined(LD_GAME_BANDIT_H_) #define LD_GAME_BANDIT_H_ +#include "outfit.h" typedef enum BANDIT_ACTION BANDIT_ACTION; enum BANDIT_ACTION @@ -62,8 +63,12 @@ struct Bandit { F32 accuracyRange; // A the circle around the bandit where they will trigger the quicktime reaction scene 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 V2f ShootTowards(Bandit* bandit, V2f target, Random* r); +function void BanditDraw(D_Context *draw, Bandit *bandit); #endif // LD_GAME_BANDIT_H_ diff --git a/code/game/impl/bandit.c b/code/game/impl/bandit.c index 858eda1..900ab8b 100644 --- a/code/game/impl/bandit.c +++ b/code/game/impl/bandit.c @@ -1,7 +1,7 @@ #include "game/world.h" #include "game/bandit.h" -V2f shootTowards(Bandit *bandit, V2f target, Random* r) +V2f ShootTowards(Bandit *bandit, V2f target, Random* r) { V2f shooterV2 = bandit->collision.pos; F32 randX = Random_F32(r, -bandit->accuracyRange, bandit->accuracyRange); @@ -71,17 +71,17 @@ void UpdateBandit(F32 delta, Bandit *bandit, World *world) { bandit->reloadTimer -= delta; if (bandit->shootCooldownTimer < 0 && bandit->reloadTimer < 0) { - printf("shoot at player\n"); + printf("\nshoot at player"); bandit->bullets--; bandit->shootCooldownTimer = bandit->shootDelay; - V2f banditShot = shootTowards(bandit, world->player.collision.pos, &world->random); + V2f banditShot = ShootTowards(bandit, world->player.collision.pos, &world->random); if(AABB_Slab(bandit->collision.pos, banditShot, world->player.collision)){ // gets shot lmao - printf("hit\n"); + printf("\nhit"); world->player.health--; } if(bandit->bullets == 0){ - printf("enemy reload\n"); + printf("\nenemy reload"); bandit->bullets = 6; bandit->reloadTimer = bandit->reloadTime; } @@ -90,3 +90,23 @@ void UpdateBandit(F32 delta, Bandit *bandit, World *world) { // 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); + } + } +} \ No newline at end of file diff --git a/code/game/impl/npc.c b/code/game/impl/npc.c index 7be61d0..974c9ef 100644 --- a/code/game/impl/npc.c +++ b/code/game/impl/npc.c @@ -46,3 +46,23 @@ void UpdateNPC(F32 delta, NPC *npc, World *world) { 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); + } + } +} \ No newline at end of file diff --git a/code/game/impl/outfit.c b/code/game/impl/outfit.c new file mode 100644 index 0000000..fbe15d7 --- /dev/null +++ b/code/game/impl/outfit.c @@ -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; +} \ No newline at end of file diff --git a/code/game/impl/player.c b/code/game/impl/player.c index 6585f3f..7192030 100644 --- a/code/game/impl/player.c +++ b/code/game/impl/player.c @@ -2,47 +2,9 @@ #include #include #include +#include "outfit.h" +#include -// @Todo: move/extern these so the npc/bandit can use them -// -#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)) void PlayerInit(G_State *game, Player *player) { World *world = game->world; @@ -105,6 +67,16 @@ void PlayerInput(SDL_Event *event, Player *player) player->controls.downDown = val; break; } + case SDLK_E: + { + for(int i = 0; player->world->npmCount; 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 ( diff --git a/code/game/impl/world.c b/code/game/impl/world.c index e979e52..9ed19e3 100644 --- a/code/game/impl/world.c +++ b/code/game/impl/world.c @@ -67,15 +67,11 @@ void RenderWorld(World *world, D_Context *draw) { for(U32 i = 0; i < world->npcCount; i++) { NPC npc = world->npcs[i]; if(npc.currentArea == world->player.currentArea) { - V2f drawPos = AABB_Centre(npc.collision); - D_Rect(draw, drawPos.x, drawPos.y, .texture = 1); + NPCDraw(draw, &world->npcs[i]); } } - if(world->bandit.currentArea == world->player.currentArea) { - V2f drawPos = AABB_Centre(world->bandit.collision); - D_Rect(draw, drawPos.x, drawPos.y, .texture = 9); - } + BanditDraw(draw, &world->bandit); PlayerDraw(draw, &world->player); } diff --git a/code/game/npc.h b/code/game/npc.h index eff6157..8ff3512 100644 --- a/code/game/npc.h +++ b/code/game/npc.h @@ -46,10 +46,15 @@ struct NPC { U32 targetNavNode; // How long the npc has been walking to the next index F32 walkTimer; - + // Space within you can interact with the NPC. + F32 interationRadius; //// Knowledge // What the NPC knows about the bandit. 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_ diff --git a/code/game/outfit.h b/code/game/outfit.h new file mode 100644 index 0000000..27a54cb --- /dev/null +++ b/code/game/outfit.h @@ -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 \ No newline at end of file diff --git a/code/game/player.h b/code/game/player.h index 441793e..b6986f1 100644 --- a/code/game/player.h +++ b/code/game/player.h @@ -34,6 +34,9 @@ struct Player U32 health; F32 reloadTimer; + + U32 *knownDetails; + U32 detailCount; }; function void PlayerInit(G_State *game, Player *player); diff --git a/code/game/world.h b/code/game/world.h index 6977581..6383399 100644 --- a/code/game/world.h +++ b/code/game/world.h @@ -67,7 +67,7 @@ struct World { World_Hitbox *hitboxes; World_Portal *portals; U32 *map; - + bool showPoster; U32 propCount; U32 portalCount; U32 hitboxCount; From 31863b0d3194b9cea4c58fc3486663a3bfdbb1b9 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 6 Oct 2025 23:09:53 +0100 Subject: [PATCH 2/3] fix: import --- code/game/impl/player.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/impl/player.c b/code/game/impl/player.c index 7192030..cfeaae4 100644 --- a/code/game/impl/player.c +++ b/code/game/impl/player.c @@ -2,7 +2,7 @@ #include #include #include -#include "outfit.h" +#include "../outfit.h" #include From 8363560fd2d244ebd3f4c1e50e3b6f56db5eb383 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 6 Oct 2025 23:13:46 +0100 Subject: [PATCH 3/3] fix: make it compile --- code/game/impl/player.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/impl/player.c b/code/game/impl/player.c index cfeaae4..8579c39 100644 --- a/code/game/impl/player.c +++ b/code/game/impl/player.c @@ -3,7 +3,7 @@ #include #include #include "../outfit.h" -#include +#include "../npc.h" void PlayerInit(G_State *game, Player *player) { @@ -69,11 +69,11 @@ void PlayerInput(SDL_Event *event, Player *player) } case SDLK_E: { - for(int i = 0; player->world->npmCount; i++){ - NPC *npc = player->world->npcs[i]; + 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]; + player->knownDetails[player->detailCount] = player->world->bandit.outfitChoices[player->detailCount]; } } }