#include "../world.h" #include "../npc.h" #include "../player.h" #include "../aabb.h" #include #include #include #include "../map.h" void UpdateWorld(F32 delta, World *world) { if(world->bandit.mode == BANDIT_SHOOTOUT){ delta = delta/4; } UpdateBandit(delta, &world->bandit, world); UpdateNPCs(delta, world); PlayerUpdate(delta, &world->player); } void UpdateNPCs(F32 delta, World *world) { for (U32 i = 0; i < world->npcCount; i++) { NPC *npc = &world->npcs[i]; UpdateNPC(delta, npc, world); if ( 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)); } } } void ProcessEvents(SDL_Event *event, World *world) { PlayerInput(event, &world->player); if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F5){ SaveWorld(world); } if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_F6){ LoadWorld(world->arena, world); } } void RenderWorld(World *world, D_Context *draw) { if(world->player.currentArea == WORLD_AREA_OUTSIDE) { for (int i = 0; i < 4800; i++) { D_Rect( draw, (F32) (i % 96), (F32) (i / 96), .texture = D_ImageHandle(draw,world->tileTypes[world->map[i]].tag), .angle = (F32) world->tileTypes[world->map[i]].rotation, ); } } for (U32 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, .texture = D_ImageHandle(draw,world->propTypes[world->props[i].propType].tag), .scale = world->propTypes[world->props[i].propType].scale, ); } } for(U32 i = 0; i < world->npcCount; i++) { NPC npc = world->npcs[i]; if(npc.currentArea == world->player.currentArea) { NPCDraw(draw, &world->npcs[i]); } } BanditDraw(draw, &world->bandit); 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); U64 offset = 0; for (U32 i = 0; i < WORLD_TILE_TYPE_MAX; i++) { World_Tile *tile = &world->tileTypes[i]; 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]; WRITE(type->tag.count); WRITEN(type->tag.data, type->tag.count); WRITE(type->scale); } WRITE(world->propCount); WRITEN(world->props, WORLD_PROP_MAX); WRITE(world->hitboxCount); WRITEN(world->hitboxes, WORLD_HITBOX_MAX); WRITEN(world->map, WORLD_MAP_MAX); WRITE(world->portalCount); WRITEN(world->portals, WORLD_PORTAL_MAX); FS_FileClose(file); printf("--- World Saved ---\n"); } void LoadWorld(M_Arena *arena, World *world) { printf("--- Loading World ---\n"); 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); for (U32 it = 0; it < WORLD_TILE_TYPE_MAX; ++it) { World_Tile *type = &world->tileTypes[it]; Str8 name; name.count = *(S64 *) base; name.data = base + 8; 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); 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; 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); M_CopySize(world->map, __map, WORLD_MAP_MAX * sizeof(U32)); 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"); } 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) { 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); 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 = cast(F32) x; world->navMesh->nodes[world->navMesh->nodeCount].pos.y = cast(F32) y; world->navMesh->nodes[world->navMesh->nodeCount].connectionCount = 0; for(int nx = -1; nx < 2; nx++){ for(int ny = -1; ny < 2; ny++){ if(nx==0 && ny==0) {continue;} if(x+nx < 0 || x+nx > 95) { continue; } if(y+ny < 0 || y+ny > 49) { continue; } // 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; S32 index = -1; for (U32 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 > (S32) 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].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[index].connectionCount++; } } world->navMesh->nodeCount++; } for(U32 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; } }