2025-10-05 14:42:19 +01:00
|
|
|
#include "../world.h"
|
|
|
|
|
#include "../npc.h"
|
|
|
|
|
#include "../player.h"
|
2025-10-05 22:35:34 +01:00
|
|
|
#include "../aabb.h"
|
2025-10-05 14:42:19 +01:00
|
|
|
#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 14:42:19 +01:00
|
|
|
|
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);
|
2025-10-05 14:42:19 +01:00
|
|
|
UpdateNPCs(delta, world);
|
2025-10-05 18:05:01 +01:00
|
|
|
PlayerUpdate(delta, &world->player);
|
2025-10-05 14:42:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-10-05 16:05:57 +01:00
|
|
|
void UpdateNPCs(F32 delta, World *world)
|
|
|
|
|
{
|
|
|
|
|
for (U32 i = 0; i < world->npcCount; i++)
|
|
|
|
|
{
|
2025-10-05 23:36:50 +01:00
|
|
|
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)
|
|
|
|
|
{
|
2025-10-05 23:36:50 +01:00
|
|
|
printf("You shot %*.s\n", Sv(world->npcs[i].name));
|
2025-10-05 21:05:29 +01:00
|
|
|
}
|
2025-10-05 14:42:19 +01:00
|
|
|
}
|
2025-10-05 15:17:37 +01:00
|
|
|
}
|
2025-10-05 14:42:19 +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){
|
|
|
|
|
SaveWorld(world->arena, world);
|
|
|
|
|
}
|
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 14:42:19 +01:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
for (int i = 0; i < world->propCount; i++) {
|
|
|
|
|
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,
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-10-05 21:19:14 +01:00
|
|
|
for(U32 i = 0; i < world->npcCount; i++) {
|
2025-10-05 21:05:29 +01:00
|
|
|
NPC npc = world->npcs[i];
|
2025-10-05 23:36:50 +01:00
|
|
|
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
|
|
|
}
|
2025-10-05 21:19:14 +01:00
|
|
|
D_Rect(draw, world->player.pos.x, world->player.pos.y, .texture = 1);
|
2025-10-05 14:42:19 +01:00
|
|
|
}
|
2025-10-05 21:11:18 +01:00
|
|
|
|
2025-10-06 01:10:44 +01:00
|
|
|
void SaveWorld(M_Arena *arena, World *world) {
|
|
|
|
|
printf("Saving world\n");
|
2025-10-06 01:49:10 +01:00
|
|
|
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_WRITE);
|
2025-10-06 16:35:22 +01:00
|
|
|
U32 offset = 0;
|
|
|
|
|
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
|
|
|
|
|
FS_FileWrite(file, &world->tileTypes[i].tag.count, sizeof(S64), offset);
|
|
|
|
|
offset += sizeof(S64);
|
|
|
|
|
FS_FileWrite(file, world->tileTypes[i].tag.data, world->tileTypes[i].tag.count, offset);
|
|
|
|
|
offset += sizeof(U8) * world->tileTypes[i].tag.count;
|
|
|
|
|
FS_FileWrite(file, &world->tileTypes[i].rotation, sizeof(F32), offset);
|
|
|
|
|
offset += sizeof(F32);
|
|
|
|
|
}
|
|
|
|
|
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->propCount, sizeof(U32), offset);
|
|
|
|
|
offset += sizeof(U32);
|
|
|
|
|
|
|
|
|
|
FS_FileWrite(file, world->props, sizeof(World_Prop)*WORLD_PROP_MAX, offset);
|
|
|
|
|
offset += sizeof(World_Prop)*WORLD_PROP_MAX;
|
|
|
|
|
|
|
|
|
|
FS_FileWrite(file, &world->hitboxCount, sizeof(U32), offset);
|
|
|
|
|
offset += sizeof(U32);
|
|
|
|
|
|
|
|
|
|
FS_FileWrite(file, world->hitboxes, sizeof(AABB)*WORLD_HITBOX_MAX, offset);
|
|
|
|
|
offset += sizeof(AABB)*WORLD_HITBOX_MAX;
|
|
|
|
|
|
|
|
|
|
FS_FileWrite(file, world->map, sizeof(U32)*WORLD_MAP_MAX, offset);
|
|
|
|
|
offset += sizeof(U32)*WORLD_MAP_MAX;
|
|
|
|
|
|
2025-10-06 01:49:10 +01:00
|
|
|
FS_FileClose(file);
|
|
|
|
|
printf("Saved world :)\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 01:49:10 +01:00
|
|
|
printf("loading world\n");
|
2025-10-06 11:31:35 +01:00
|
|
|
OS_Handle file = FS_FileOpen(S("world.sgdat"), FS_ACCESS_READ);
|
2025-10-06 16:35:22 +01:00
|
|
|
U32 offset = 0;
|
|
|
|
|
|
|
|
|
|
world->tileTypes = M_ArenaPush(arena, World_Tile, .count=WORLD_TILE_TYPE_MAX);
|
|
|
|
|
for(int i = 0; i < WORLD_TILE_TYPE_MAX; i++) {
|
|
|
|
|
FS_FileRead(file, &world->tileTypes[i].tag.count, sizeof(S64), offset);
|
|
|
|
|
offset += sizeof(S64);
|
|
|
|
|
world->tileTypes[i].tag.data = M_ArenaPush(arena, U8, .count=world->tileTypes[i].tag.count);
|
|
|
|
|
FS_FileRead(file, world->tileTypes[i].tag.data, world->tileTypes[i].tag.count, offset);
|
|
|
|
|
offset += sizeof(U8) * world->tileTypes[i].tag.count;
|
|
|
|
|
FS_FileRead(file, &world->tileTypes[i].rotation, sizeof(F32), offset);
|
|
|
|
|
offset += sizeof(F32);
|
|
|
|
|
}
|
|
|
|
|
world->propTypes = M_ArenaPush(arena, World_PropType, .count=WORLD_PROP_TYPE_MAX);
|
|
|
|
|
for(int i = 0; i < WORLD_PROP_TYPE_MAX; i++) {
|
|
|
|
|
FS_FileRead(file, &world->propTypes[i].tag.count, sizeof(S64), offset);
|
|
|
|
|
offset += sizeof(S64);
|
|
|
|
|
world->propTypes[i].tag.data = M_ArenaPush(arena, U8, .count=world->propTypes[i].tag.count);
|
|
|
|
|
FS_FileRead(file, world->propTypes[i].tag.data, world->propTypes[i].tag.count, offset);
|
|
|
|
|
offset += sizeof(U8) * world->propTypes[i].tag.count;
|
|
|
|
|
FS_FileRead(file, &world->propTypes[i].scale, sizeof(F32), offset);
|
|
|
|
|
offset += sizeof(F32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FS_FileRead(file, &world->propCount, sizeof(U32), offset);
|
|
|
|
|
offset += sizeof(U32);
|
|
|
|
|
|
|
|
|
|
world->props = M_ArenaPush(arena, World_Prop, .count=WORLD_PROP_MAX);
|
|
|
|
|
FS_FileRead(file, world->props, sizeof(World_Prop)*WORLD_PROP_MAX, offset);
|
2025-10-06 19:27:45 +01:00
|
|
|
offset += sizeof(World_Prop)*WORLD_PROP_MAX;
|
2025-10-06 16:35:22 +01:00
|
|
|
|
|
|
|
|
FS_FileRead(file, &world->hitboxCount, sizeof(U32), offset);
|
|
|
|
|
offset += sizeof(U32);
|
|
|
|
|
|
|
|
|
|
world->hitboxes = M_ArenaPush(arena, AABB, .count=WORLD_HITBOX_MAX);
|
|
|
|
|
FS_FileRead(file, world->hitboxes, sizeof(AABB)*WORLD_HITBOX_MAX, offset);
|
2025-10-06 19:27:45 +01:00
|
|
|
offset += sizeof(AABB)*WORLD_HITBOX_MAX;
|
2025-10-06 16:35:22 +01:00
|
|
|
|
|
|
|
|
world->map = M_ArenaPush(arena, U32, .count=WORLD_MAP_MAX);
|
|
|
|
|
FS_FileRead(file, world->map, sizeof(U32)*WORLD_MAP_MAX, offset);
|
|
|
|
|
offset += sizeof(U32)*WORLD_MAP_MAX;
|
|
|
|
|
|
2025-10-06 01:49:10 +01:00
|
|
|
FS_FileClose(file);
|
|
|
|
|
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);
|
2025-10-06 19:27:45 +01:00
|
|
|
bool skip = false;
|
|
|
|
|
for(int hi = 0; hi < world->hitboxCount; hi++) {
|
|
|
|
|
if(AABB_Point(world->hitboxes[hi], V2F(x, y))) {
|
|
|
|
|
skip = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(skip) {continue;}
|
2025-10-06 18:23:47 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2025-10-06 19:27:45 +01:00
|
|
|
// It's quad for loop time :D
|
|
|
|
|
for(int hi = 0; hi < world->hitboxCount; hi++) {
|
|
|
|
|
if(AABB_Point(world->hitboxes[hi], V2F(x+nx, y+ny))) {
|
|
|
|
|
skip = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(skip) {continue;}
|
2025-10-06 18:23:47 +01:00
|
|
|
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++;
|
|
|
|
|
}
|
|
|
|
|
}
|