Files
ld58/code/game/impl/world.c

260 lines
6.9 KiB
C
Raw Normal View History

#include "../world.h"
#include "../npc.h"
#include "../player.h"
2025-10-05 22:35:34 +01:00
#include "../aabb.h"
#include <SDL3/SDL_events.h>
2025-10-06 01:10:44 +01:00
#include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_oldnames.h>
2025-10-06 00:38:10 +01:00
#include "../map.h"
2025-10-05 16:05:57 +01:00
void UpdateWorld(F32 delta, World *world)
{
2025-10-05 21:05:29 +01:00
UpdateBandit(delta, &world->bandit, world);
UpdateNPCs(delta, world);
2025-10-05 18:05:01 +01:00
PlayerUpdate(delta, &world->player);
}
2025-10-05 16:05:57 +01:00
void UpdateNPCs(F32 delta, World *world)
{
for (U32 i = 0; i < world->npcCount; i++)
{
NPC *npc = &world->npcs[i];
UpdateNPC(delta, npc, world);
2025-10-06 00:48:41 +01:00
if (
world->player.controls.shot && AABB_Slab(world->player.pos, world->player.shotPos, npc->collision) && npc->currentArea == world->player.currentArea)
{
printf("You shot %*.s\n", Sv(world->npcs[i].name));
2025-10-05 21:05:29 +01:00
}
}
}
2025-10-05 16:05:57 +01:00
void ProcessEvents(SDL_Event *event, World *world)
{
2025-10-05 18:05:01 +01:00
PlayerInput(event, &world->player);
2025-10-06 01:10:44 +01:00
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){
2025-10-06 19:36:41 +01:00
SaveWorld(world);
2025-10-06 01:10:44 +01:00
}
2025-10-06 16:35:22 +01:00
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F6){
LoadWorld(world->arena, world);
}
}
2025-10-05 16:49:18 +01:00
void RenderWorld(World *world, D_Context *draw) {
2025-10-06 14:50:32 +01:00
if(world->player.currentArea == WORLD_AREA_OUTSIDE) {
for (int i = 0; i < 4800; i++) {
D_Rect(
draw,
(F32) (i % 96), (F32) (i / 96),
2025-10-06 16:35:22 +01:00
.texture = D_ImageHandle(draw,world->tileTypes[world->map[i]].tag),
2025-10-06 14:50:32 +01:00
.angle = (F32) world->tileTypes[world->map[i]].rotation,
);
}
2025-10-06 14:26:00 +01:00
}
2025-10-06 19:36:41 +01:00
for (U32 i = 0; i < world->propCount; i++) {
2025-10-06 14:26:00 +01:00
if(world->props[i].area == world->player.currentArea) {
D_Rect(
draw,
world->props[i].pos.x,
world->props[i].pos.y,
2025-10-06 16:35:22 +01:00
.texture = D_ImageHandle(draw,world->propTypes[world->props[i].propType].tag),
2025-10-06 14:26:00 +01:00
.scale = world->propTypes[world->props[i].propType].scale,
);
}
2025-10-06 00:38:10 +01:00
}
2025-10-06 18:23:47 +01:00
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++) {
2025-10-05 21:05:29 +01:00
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);
}
}
if(world->bandit.currentArea == world->player.currentArea) {
V2f drawPos = AABB_Centre(world->bandit.collision);
D_Rect(draw, drawPos.x, drawPos.y, .texture = 9);
2025-10-05 16:49:18 +01:00
}
D_Rect(draw, world->player.pos.x, world->player.pos.y, .texture = 1);
}
2025-10-06 19:36:41 +01:00
#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);
2025-10-06 01:49:10 +01:00
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE);
2025-10-06 19:36:41 +01:00
U64 offset = 0;
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
for (U32 i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
World_Tile *tile = &world->tileTypes[i];
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
WRITE(tile->tag.count);
WRITEN(tile->tag.data, tile->tag.count);
WRITE(tile->rotation);
}
for (U32 i = 0; i < WORLD_PROP_TYPE_MAX; i++) {
World_PropType *type = &world->propTypes[i];
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
WRITE(type->tag.count);
WRITEN(type->tag.data, type->tag.count);
WRITE(type->scale);
}
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
WRITE(world->propCount);
WRITEN(world->props, WORLD_PROP_MAX);
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
WRITE(world->hitboxCount);
WRITEN(world->hitboxes, WORLD_HITBOX_MAX);
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
WRITEN(world->map, WORLD_MAP_MAX);
2025-10-06 16:35:22 +01:00
2025-10-06 01:49:10 +01:00
FS_FileClose(file);
2025-10-06 19:36:41 +01:00
printf("--- World Saved ---\n");
2025-10-06 01:10:44 +01:00
}
2025-10-06 16:35:22 +01:00
void LoadWorld(M_Arena *arena, World *world) {
2025-10-06 19:36:41 +01:00
printf("--- Loading World ---\n");
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
M_TempScope(0, 0) {
Str8 data = FS_ReadEntireFile(temp.arena, S("world.sgdat"));
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
U8 *base = data.data;
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
// Load tile types
//
world->tileTypes = M_ArenaPush(arena, World_Tile, .count = WORLD_TILE_TYPE_MAX);
for (U32 it = 0; it < WORLD_TILE_TYPE_MAX; ++it) {
World_Tile *type = &world->tileTypes[it];
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
Str8 name;
name.count = *(S64 *) base;
name.data = base + 8;
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
base += 8;
base += name.count;
2025-10-06 16:35:22 +01:00
2025-10-06 19:36:41 +01:00
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);
for (U32 it = 0; it < WORLD_PROP_TYPE_MAX; ++it) {
World_PropType *type = &world->propTypes[it];
Str8 name;
name.count = *(S64 *) base;
name.data = base + 8;
base += 8;
base += name.count;
if (name.count != 0) {
type->tag = Str8_Copy(arena, name);
type->scale = *(F32 *) base;
}
base += 4;
}
// 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);
M_CopySize(world->props, props, n_props * sizeof(World_Prop));
base += (WORLD_PROP_MAX * sizeof(World_Prop));
}
// Hitboxes
//
{
U32 n_hitbox = *(U32 *) base; base += 4;
AABB *boxes = (AABB *) base;
world->hitboxCount = n_hitbox;
world->hitboxes = M_ArenaPush(arena, AABB, .count = WORLD_HITBOX_MAX);
M_CopySize(world->hitboxes, boxes, n_hitbox * sizeof(AABB));
base += (WORLD_HITBOX_MAX * sizeof(AABB));
}
// Map
//
{
U32 *__map = (U32 *) base;
world->map = M_ArenaPush(arena, U32, .count = WORLD_MAP_MAX);
M_CopySize(world->map, __map, WORLD_MAP_MAX * sizeof(U32));
base += (WORLD_MAP_MAX * sizeof(U32));
}
if (base != (data.data + data.count)) {
printf("--- OFFSET MISMATCH ---\n");
}
printf(" - %d props\n", world->propCount);
printf(" - %d hitboxes\n", world->hitboxCount);
printf("--- Loaded World ---\n");
}
2025-10-06 01:10:44 +01:00
}
2025-10-06 18:23:47 +01:00
void GenerateNavMesh(M_Arena *arena, World *world) {
world->navMesh = M_ArenaPush(arena, NavMesh);
world->navMesh->nodeCount = 0;
for(int i = 0; i < WORLD_MAP_MAX; i++) {
U32 x = (i % 96);
U32 y = (i / 96);
world->navMesh->nodes[world->navMesh->nodeCount].pos.x = x;
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;
for(int nx = -1; nx < 2; nx++){
for(int ny = -1; ny < 2; ny++){
if((nx==ny) && nx==0) {continue;}
if(x+nx < 0 || x+nx > 95) {
continue;
}
if(y+ny < 0 || y+ny > 49) {
continue;
}
U32 index = x+nx + (y+ny)*96;
U32 nCount = world->navMesh->nodeCount;
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].connectionCount++;
}
}
world->navMesh->nodeCount++;
}
}