diff --git a/assets/main_game_level.bin b/assets/main_game_level.bin new file mode 100644 index 0000000..d5bec8b Binary files /dev/null and b/assets/main_game_level.bin differ diff --git a/main.c b/main.c index 07b3906..a74f9a0 100644 --- a/main.c +++ b/main.c @@ -219,6 +219,19 @@ String8 nullterm(Arena *copy_onto, String8 to_nullterm) return to_return; } +// all utilities that depend on md.h strings or look like md.h stuff in general +#define PushWithLint(arena, list, ...) { S8ListPushFmt(arena, list, __VA_ARGS__); if(false) printf( __VA_ARGS__); } +#define FmtWithLint(arena, ...) (0 ? printf(__VA_ARGS__) : (void)0, S8Fmt(arena, __VA_ARGS__)) + +void WriteEntireFile(char *null_terminated_path, String8 data) { + FILE* file = fopen(null_terminated_path, "wb"); + if(file) { + fwrite(data.str, 1, data.size, file); + fclose(file); + } else { + Log("Failed to open file %s and save data.\n", null_terminated_path) + } +} double clamp(double d, double min, double max) { @@ -2268,42 +2281,35 @@ void transition_to_room(GameState *gs, ThreeDeeLevel *level, u64 new_roomid) gs->current_roomid = new_roomid; } -void initialize_gamestate_from_threedee_level(GameState *gs, ThreeDeeLevel *level) -{ - if (gs->arena) - { - ArenaRelease(gs->arena); - } - memset(gs, 0, sizeof(GameState)); - gs->arena = ArenaAlloc(); - rnd_gamerand_seed(&gs->random, RANDOM_SEED); - - // make entities for all rooms - for (Room *cur_room = level->room_list_first; cur_room; cur_room = cur_room->next) - { - for (PlacedEntity *cur = cur_room->placed_entity_list; cur; cur = cur->next) - { - assert(false); // need to decide on a way entitie kind is decided on - Entity *cur_entity = new_entity(gs); - cur_entity->npc_kind = cur->npc_kind; - cur_entity->pos = point_plane(cur->t.offset); - cur_entity->current_roomid = cur_room->roomid; +// no crash or anything bad if called on an already cleaned up gamestate +void cleanup_gamestate(GameState *gs) { + if(gs) { + if(gs->arena) { + ArenaRelease(gs->arena); } + memset(gs, 0, sizeof(GameState)); } +} - gs->world_entity = new_entity(gs); - gs->world_entity->is_world = true; - +// this can be called more than once, it cleanly handles all states of the gamestate +void initialize_gamestate(GameState *gs, u64 roomid) { + if(!gs->arena) gs->arena = ArenaAlloc(); + if(!gs->world_entity) { + gs->world_entity = new_entity(gs); + gs->world_entity->is_world = true; + } + gs->current_roomid = roomid; + rnd_gamerand_seed(&gs->random, RANDOM_SEED); #ifdef DEVTOOLS gs->edit.enabled = true; #endif - - transition_to_room(gs, &level_threedee, level->room_list_first->roomid); } void reset_level() { - initialize_gamestate_from_threedee_level(&gs, &level_threedee); + Log("STUB\n"); + // you prob want to do something like all dead entities are alive and reset to their editor positions. + // This means entities need an editor spawnpoint position and a gameplay position.... } enum @@ -2428,7 +2434,19 @@ void ser_Npc(SerState *ser, Npc *npc) { ser_TextChunk(ser, &npc->name); ser_int(ser, &npc->kind); - ser_TextChunk(ser, &npc->prompt); +} + +void ser_EditorState(SerState *ser, EditorState *ed) { + ser_bool(ser, &ed->enabled); + ser_u64(ser, &ed->current_roomid); + ser_Vec2(ser, &ed->camera_panning_target); + ser_Vec2(ser, &ed->camera_panning); + ser_NpcKind(ser, &ed->placing_npc); + ser_NpcKind(ser, &ed->editing_npc); + + ser_bool(ser, &ed->placing_spawn); + ser_u64(ser, &ed->player_spawn_roomid); + ser_Vec2(ser, &ed->player_spawn_position); } void ser_GameState(SerState *ser, GameState *gs) @@ -2444,6 +2462,8 @@ void ser_GameState(SerState *ser, GameState *gs) ser_uint64_t(ser, &gs->tick); ser_bool(ser, &gs->won); + ser_EditorState(ser, &gs->edit); + ser_double(ser, &gs->time); SER_BUFF(ser, Npc, &gs->characters); @@ -2459,7 +2479,6 @@ void ser_GameState(SerState *ser, GameState *gs) ser_entity(ser, &(gs->entities[i])); } } - gs->world_entity = 0; if (!ser->cur_error.failed) { @@ -2476,6 +2495,9 @@ void ser_GameState(SerState *ser, GameState *gs) ser->cur_error = (SerError){.failed = true, .why = S8Lit("No world entity found in deserialized entities")}; } } + + if(!ser->serializing) + initialize_gamestate(gs, gs->current_roomid); } // error_out is allocated onto arena if it fails @@ -2525,7 +2547,7 @@ String8 save_to_string(Arena *output_bytes_arena, Arena *error_arena, String8 *e // error strings are allocated on error_arena, probably scratch for that. If serialization fails, // nothing is allocated onto arena, the allocations are rewound // If there was an error, the gamestate returned might be partially constructed and bad. Don't use it -GameState load_from_string(Arena *arena, Arena *error_arena, String8 data, String8 *error_out) +GameState *load_from_string(Arena *arena, Arena *error_arena, String8 data, String8 *error_out) { ArenaTemp temp = ArenaBeginTemp(arena); @@ -2536,10 +2558,11 @@ GameState load_from_string(Arena *arena, Arena *error_arena, String8 data, Strin .arena = temp.arena, .error_arena = error_arena, }; - GameState to_return = {0}; - ser_GameState(&ser, &to_return); + GameState *to_return = PushArrayZero(temp.arena, GameState, 1); + ser_GameState(&ser, to_return); if (ser.cur_error.failed) { + cleanup_gamestate(to_return); ArenaEndTemp(temp); // no allocations if it fails *error_out = ser.cur_error.why; } @@ -3322,7 +3345,22 @@ void init(void) ArenaClear(frame_arena); - reset_level(); + cleanup_gamestate(&gs); + bool loaded_from_file = false; + { + String8 game_file = LoadEntireFile(frame_arena, S8Lit("assets/main_game_level.bin")); + String8 error = {0}; + GameState *deserialized_gs = load_from_string(frame_arena, frame_arena, game_file, &error); + + if(error.size == 0) { + gs = *deserialized_gs; + loaded_from_file = true; + } else { + Log("Failed to load from saved gamestate: %.*s\n", S8VArg(error)); + } + } + if(!loaded_from_file) + initialize_gamestate(&gs, level_threedee.room_list_first->roomid); #ifdef DEVTOOLS do_metadesk_tests(); @@ -7089,6 +7127,26 @@ void frame(void) } #ifdef DEVTOOLS + if(gs.edit.enabled && pressed.mouse_up) { + String8 error = {0}; + Log("Saving gamestate...\n"); + String8 saved = save_to_string(frame_arena, frame_arena, &error, &gs); + if(error.size > 0) { + Log("Failed to save gamestate: %.*s\n", S8VArg(error)); + } else { + WriteEntireFile((char*)nullterm(frame_arena, S8Lit("assets/main_game_level.bin")).str, saved); + } + // reload from the saved data to make sure that functionality works + if(error.size == 0) { + GameState *deserialized_gs = load_from_string(frame_arena, frame_arena, saved, &error); + if(error.size == 0) { + cleanup_gamestate(&gs); + gs = *deserialized_gs; + } else { + Log("Failed to load from saved gamestate: %.*s\n", S8VArg(error)); + } + } + } // statistics @Place(devtools drawing developer menu drawing) if (show_devtools) PROFILE_SCOPE("devtools drawing") diff --git a/makeprompt.h b/makeprompt.h index 06305b6..c6c847d 100644 --- a/makeprompt.h +++ b/makeprompt.h @@ -16,8 +16,6 @@ // Never expected such a stupid stuff from such a great director. If there is 0 stari can give that or -200 to this movie. Its worst to see and unnecessary loss of money -#define PushWithLint(arena, list, ...) { S8ListPushFmt(arena, list, __VA_ARGS__); if(false) printf( __VA_ARGS__); } -#define FmtWithLint(arena, ...) (0 ? printf(__VA_ARGS__) : (void)0, S8Fmt(arena, __VA_ARGS__)) typedef BUFF(char, 1024 * 10) Escaped; @@ -359,14 +357,14 @@ typedef struct Target { TextChunk name; TextChunk description; TargetKind kind; -} Target; +} SituationTarget; // the situation for somebody typedef struct CharacterSituation { TextChunk goal; // kind of like the most important memory, self described character's goal right now TextChunk memories[4]; // explicit numbered memories BUFF(TextChunk, 5) events; // events that this character has observed in the plain english form - BUFF(Target, 10) targets; + BUFF(Target, 10) SituationTarget; CharacterStatus my_status; CharacterStatus status; diff --git a/utility.h b/utility.h index 8f76ffb..13d903e 100644 --- a/utility.h +++ b/utility.h @@ -2,6 +2,7 @@ #include + #define STRINGIZE(x) STRINGIZE2(x) #define STRINGIZE2(x) #x @@ -25,3 +26,4 @@ #define assert game_assert #define Log(...) { printf("%s Log %d | ", __FILE__, __LINE__); printf(__VA_ARGS__); } +