diff --git a/assets/main_game_level.bin b/assets/main_game_level.bin index d5bec8b..f2897f3 100644 Binary files a/assets/main_game_level.bin and b/assets/main_game_level.bin differ diff --git a/main.c b/main.c index a74f9a0..c539644 100644 --- a/main.c +++ b/main.c @@ -909,6 +909,20 @@ AABB entity_aabb(Entity *e) return entity_aabb_at(e, at); } +Entity *player(GameState *gs) { + ENTITIES_ITER(gs->entities) { + if(it->is_player) return it; + } + return 0; +} + +Entity *world(GameState *gs) { + ENTITIES_ITER(gs->entities) { + if(it->is_world) return it; + } + return 0; +} + typedef struct LoadedImage { struct LoadedImage *next; @@ -2294,15 +2308,12 @@ void cleanup_gamestate(GameState *gs) { // 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; + if(!world(gs)) { + Entity *world = new_entity(gs); + world->is_world = true; } gs->current_roomid = roomid; rnd_gamerand_seed(&gs->random, RANDOM_SEED); -#ifdef DEVTOOLS - gs->edit.enabled = true; -#endif } void reset_level() @@ -2315,6 +2326,7 @@ void reset_level() enum { V0, + V1, VMax, } Version; @@ -2353,8 +2365,9 @@ void ser_entity(SerState *ser, Entity *e) ser_float(ser, &e->damage); ser_bool(ser, &e->is_world); - ser_bool(ser, &e->is_npc); + ser_bool(ser, &e->is_player); + ser_bool(ser, &e->being_hovered); ser_bool(ser, &e->perceptions_dirty); @@ -2482,15 +2495,7 @@ void ser_GameState(SerState *ser, GameState *gs) if (!ser->cur_error.failed) { - ARR_ITER(Entity, gs->entities) - { - if (it->is_world) - { - gs->world_entity = it; - } - } - - if (gs->world_entity == 0) + if (world(gs) == 0) { ser->cur_error = (SerError){.failed = true, .why = S8Lit("No world entity found in deserialized entities")}; } @@ -3100,7 +3105,7 @@ void do_serialization_tests() GameState gs = {0}; initialize_gamestate_from_threedee_level(&gs, &level_threedee); - gs.player->pos = V2(50.0f, 0.0); + player(&gs)->pos = V2(50.0f, 0.0); String8 error = {0}; String8 saved = save_to_string(scratch.arena, scratch.arena, &error, &gs); @@ -3111,7 +3116,7 @@ void do_serialization_tests() initialize_gamestate_from_threedee_level(&gs, &level_threedee); gs = load_from_string(persistent_arena, scratch.arena, saved, &error); - assert(gs.player->pos.x == 50.0f); + assert(player(&gs)->pos.x == 50.0f); assert(error.size == 0); Log("Default save data size is %lld bytes\n", saved.size); @@ -4632,7 +4637,7 @@ Vec2 move_and_slide(MoveSlideParams p) // add world boxes for (CollisionCylinder *cur = get_cur_room(&gs, &level_threedee)->collision_list; cur; cur = cur->next) { - BUFF_APPEND(&to_check, ((CollisionObj){cur->bounds, gs.world_entity})); + BUFF_APPEND(&to_check, ((CollisionObj){cur->bounds, world(&gs)})); } // add entity boxes @@ -5663,10 +5668,10 @@ void frame(void) cam_target_pos.x = gs.edit.camera_panning.x; cam_target_pos.z = gs.edit.camera_panning.y; } - else if (gs.player) + else if (player(&gs)) { - cam_target_pos.x = gs.player->pos.x; - cam_target_pos.z = gs.player->pos.y; + cam_target_pos.x = player(&gs)->pos.x; + cam_target_pos.z = player(&gs)->pos.y; } // dbgline(V2(0,0), V2(500, 500)); const float vertical_to_horizontal_ratio = CAM_VERTICAL_TO_HORIZONTAL_RATIO; @@ -5812,10 +5817,11 @@ void frame(void) assert(it->is_npc); Transform draw_with = entity_transform(it); - // draw_thing((DrawnThing){.mesh = &mesh_tombstone, .t = draw_with, .outline = gete(gs.player->interacting_with) == it}); { Armature *to_use = &player_armature; + // if9! + if (it->killed) { to_use->go_to_animation = S8Lit("Die Backwards"); @@ -5830,7 +5836,7 @@ void frame(void) to_use->go_to_animation = S8Lit("Idle"); } - draw_thing((DrawnThing){.armature = to_use, .t = draw_with, .outline = gs.player && gete(gs.player->interacting_with) == it}); + draw_thing((DrawnThing){.armature = to_use, .t = draw_with, .outline = player(&gs) && gete(player(&gs)->interacting_with) == it}); if (gete(it->aiming_shotgun_at)) { @@ -6128,8 +6134,8 @@ void frame(void) // dialog bubble rendering const float text_scale = speech_bubble.text_scale; float dist = 0.0f; - if (gs.player) - dist = LenV2(SubV2(it->pos, gs.player->pos)); + if (player(&gs)) + dist = LenV2(SubV2(it->pos, player(&gs)->pos)); float bubble_factor = 1.0f - clamp01(dist / 6.0f); Vec3 bubble_pos = AddV3(plane_point(it->pos), V3(0, 1.7f, 0)); // 1.7 meters is about 5'8", average person height Vec2 head_pos = threedee_to_screenspace(bubble_pos); @@ -6249,13 +6255,13 @@ void frame(void) gs.tick += 1; - if (!gs.edit.enabled && gs.player == 0) + if (!gs.edit.enabled && player(&gs) == 0) { - gs.player = new_entity(&gs); - gs.player->is_player = true; - gs.player->is_npc = true; - gs.player->current_roomid = gs.edit.player_spawn_roomid; - gs.player->pos = gs.edit.player_spawn_position; + Entity *player = new_entity(&gs); + player->is_player = true; + player->is_npc = true; + player->current_roomid = gs.edit.player_spawn_roomid; + player->pos = gs.edit.player_spawn_position; } // process gs.entities process entities @@ -6383,7 +6389,7 @@ void frame(void) it->words_said_on_page += 1; it->characters_of_word_animated = 0.0f; - float dist = LenV2(SubV2(it->pos, gs.player->pos)); + float dist = LenV2(SubV2(it->pos, player(&gs)->pos)); float volume = Lerp(-0.6f, clamp01(dist / 70.0f), -1.0f); AudioSample *possible_grunts[] = { &sound_grunt_0, @@ -6431,7 +6437,7 @@ void frame(void) // A* code if (false) { - Entity *targeting = gs.player; + Entity *targeting = player(&gs); /* G cost: distance from the current node to the start node @@ -6843,7 +6849,7 @@ void frame(void) } // @Place(process player) - if (gs.player) + if (player(&gs)) PROFILE_SCOPE("process player") { // do dialog @@ -6851,7 +6857,7 @@ void frame(void) { // find closest to talk to { - AABB dialog_rect = aabb_centered(gs.player->pos, V2(DIALOG_INTERACT_SIZE, DIALOG_INTERACT_SIZE)); + AABB dialog_rect = aabb_centered(player(&gs)->pos, V2(DIALOG_INTERACT_SIZE, DIALOG_INTERACT_SIZE)); dbgrect(dialog_rect); Overlapping possible_dialogs = get_overlapping(dialog_rect); float closest_interact_with_dist = INFINITY; @@ -6873,7 +6879,7 @@ void frame(void) if (entity_interactible) { - float dist = LenV2(SubV2((*it)->pos, gs.player->pos)); + float dist = LenV2(SubV2((*it)->pos, player(&gs)->pos)); if (dist < closest_interact_with_dist) { closest_interact_with_dist = dist; @@ -6884,7 +6890,7 @@ void frame(void) } interacting_with = closest_interact_with; - gs.player->interacting_with = frome(interacting_with); + player(&gs)->interacting_with = frome(interacting_with); } if (pressed.interact) @@ -6894,7 +6900,7 @@ void frame(void) if (closest_interact_with->is_npc) { // begin dialog with closest npc - gs.player->talking_to = frome(closest_interact_with); + player(&gs)->talking_to = frome(closest_interact_with); begin_text_input(S8Lit("")); } else @@ -6905,55 +6911,55 @@ void frame(void) } float speed = 0.0f; - if (!gs.player->killed) + if (!player(&gs)->killed) speed = PLAYER_SPEED; // velocity processing for player player movement { - gs.player->last_moved = NormV2(movement); + player(&gs)->last_moved = NormV2(movement); Vec2 target_vel = MulV2F(movement, pixels_per_meter * speed); - float player_speed = LenV2(gs.player->vel); + float player_speed = LenV2(player(&gs)->vel); float target_speed = LenV2(target_vel); - bool quick_turn = (player_speed < target_speed / 2) || DotV2(gs.player->vel, target_vel) < -0.707f; - gs.player->quick_turning_timer -= dt; + bool quick_turn = (player_speed < target_speed / 2) || DotV2(player(&gs)->vel, target_vel) < -0.707f; + player(&gs)->quick_turning_timer -= dt; if (quick_turn) { - gs.player->quick_turning_timer = 0.125f; + player(&gs)->quick_turning_timer = 0.125f; } if (quick_turn) { - gs.player->vel = target_vel; + player(&gs)->vel = target_vel; } else { // framerate-independent smoothly transition towards target (functions as friction when target is 0) - gs.player->vel = SubV2(gs.player->vel, target_vel); - gs.player->vel = MulV2F(gs.player->vel, powf(1e-8f, dt)); - gs.player->vel = AddV2(gs.player->vel, target_vel); + player(&gs)->vel = SubV2(player(&gs)->vel, target_vel); + player(&gs)->vel = MulV2F(player(&gs)->vel, powf(1e-8f, dt)); + player(&gs)->vel = AddV2(player(&gs)->vel, target_vel); } - // printf("%f%s\n", LenV2(gs.player->vel), gs.player->quick_turning_timer > 0 ? " QUICK TURN" : ""); + // printf("%f%s\n", LenV2(player(&gs)->vel), player(&gs)->quick_turning_timer > 0 ? " QUICK TURN" : ""); - gs.player->pos = move_and_slide((MoveSlideParams){gs.player, gs.player->pos, MulV2F(gs.player->vel, dt)}); + player(&gs)->pos = move_and_slide((MoveSlideParams){player(&gs), player(&gs)->pos, MulV2F(player(&gs)->vel, dt)}); bool should_append = false; // make it so no snap when new points added - if (gs.player->position_history.cur_index > 0) + if (player(&gs)->position_history.cur_index > 0) { - gs.player->position_history.data[gs.player->position_history.cur_index - 1] = gs.player->pos; + player(&gs)->position_history.data[player(&gs)->position_history.cur_index - 1] = player(&gs)->pos; } - if (gs.player->position_history.cur_index > 2) + if (player(&gs)->position_history.cur_index > 2) { - should_append = LenV2(SubV2(gs.player->position_history.data[gs.player->position_history.cur_index - 2], gs.player->pos)) > TILE_SIZE; + should_append = LenV2(SubV2(player(&gs)->position_history.data[player(&gs)->position_history.cur_index - 2], player(&gs)->pos)) > TILE_SIZE; } else { should_append = true; } if (should_append) - BUFF_QUEUE_APPEND(&gs.player->position_history, gs.player->pos); + BUFF_QUEUE_APPEND(&player(&gs)->position_history, player(&gs)->pos); } // health - if (gs.player->damage >= 1.0) + if (player(&gs)->damage >= 1.0) { reset_level(); } @@ -6984,24 +6990,24 @@ void frame(void) if (0) PROFILE_SCOPE("render player") // draw character draw player render character { - if (gs.player->position_history.cur_index > 0) + if (player(&gs)->position_history.cur_index > 0) { - float trail_len = get_total_trail_len(BUFF_MAKEREF(&gs.player->position_history)); + float trail_len = get_total_trail_len(BUFF_MAKEREF(&player(&gs)->position_history)); if (trail_len > 0.0f) // fmodf returns nan { float along = fmodf((float)elapsed_time * 100.0f, 200.0f); - Vec2 at = get_point_along_trail(BUFF_MAKEREF(&gs.player->position_history), along); + Vec2 at = get_point_along_trail(BUFF_MAKEREF(&player(&gs)->position_history), along); dbgbigsquare(at); - dbgbigsquare(get_point_along_trail(BUFF_MAKEREF(&gs.player->position_history), 50.0f)); + dbgbigsquare(get_point_along_trail(BUFF_MAKEREF(&player(&gs)->position_history), 50.0f)); } - BUFF_ITER_I(Vec2, &gs.player->position_history, i) + BUFF_ITER_I(Vec2, &player(&gs)->position_history, i) { - if (i == gs.player->position_history.cur_index - 1) + if (i == player(&gs)->position_history.cur_index - 1) { } else { - dbgline(*it, gs.player->position_history.data[i + 1]); + dbgline(*it, player(&gs)->position_history.data[i + 1]); } } } @@ -7013,7 +7019,7 @@ void frame(void) if (!mobile_controls) { float size = 100.0f; - Vec2 midpoint = MulV2F(AddV2(interacting_with->pos, gs.player->pos), 0.5f); + Vec2 midpoint = MulV2F(AddV2(interacting_with->pos, player(&gs)->pos), 0.5f); draw_quad((DrawParams){quad_centered(AddV2(midpoint, V2(0.0, 5.0f + sinf((float)elapsed_time * 3.0f) * 5.0f)), V2(size, size)), IMG(image_e_icon), blendalpha(WHITE, clamp01(1.0f - learned_e)), .layer = LAYER_UI_FG}); } @@ -7022,13 +7028,13 @@ void frame(void) } // hurt vignette - if (gs.player->damage > 0.0) + if (player(&gs)->damage > 0.0) { draw_quad((DrawParams){ (Quad){.ul = V2(0.0f, screen_size().Y), .ur = screen_size(), .lr = V2(screen_size().X, 0.0f)}, image_hurt_vignette, full_region(image_hurt_vignette), - (Color){1.0f, 1.0f, 1.0f, gs.player->damage}, + (Color){1.0f, 1.0f, 1.0f, player(&gs)->damage}, .layer = LAYER_SCREENSPACE_EFFECTS, }); } @@ -7064,7 +7070,7 @@ void frame(void) } // killed screen - if (gs.player) + if (player(&gs)) { static float visible = 0.0f; float target = 0.0f; @@ -7074,7 +7080,7 @@ void frame(void) if (it->undismissed_action) anybody_unread = true; } - if (gs.player->killed && (!anybody_unread || gs.finished_reading_dying_dialog)) + if (player(&gs)->killed && (!anybody_unread || gs.finished_reading_dying_dialog)) { gs.finished_reading_dying_dialog = true; target = 1.0f; @@ -7089,7 +7095,7 @@ void frame(void) if (imbutton(aabb_centered(V2(screen_size().x / 2.0f, screen_size().y * 0.25f), MulV2F(V2(170.0f, 60.0f), visible)), 1.5f * visible, S8Lit("Continue"))) { - gs.player->killed = false; + player(&gs)->killed = false; // transition_to_room(&gs, &level_threedee, S8Lit("StartingRoom")); reset_level(); } @@ -7127,7 +7133,7 @@ void frame(void) } #ifdef DEVTOOLS - if(gs.edit.enabled && pressed.mouse_up) { + if(pressed.mouse_up) { String8 error = {0}; Log("Saving gamestate...\n"); String8 saved = save_to_string(frame_arena, frame_arena, &error, &gs); @@ -7234,7 +7240,7 @@ void frame(void) profiling ? "yes" : "no", num_timestep_loops, flycam ? "yes" : "no", - v2varg((gs.player ? gs.player->pos : V2(0, 0)))); + v2varg((player(&gs) ? player(&gs)->pos : V2(0, 0)))); AABB bounds = draw_text((TextParams){true, stats, pos, BLACK, 1.0f}); pos.Y -= bounds.upper_left.Y - screen_size().Y; bounds = draw_text((TextParams){true, stats, pos, BLACK, 1.0f}); diff --git a/makeprompt.h b/makeprompt.h index c6c847d..64986bb 100644 --- a/makeprompt.h +++ b/makeprompt.h @@ -425,8 +425,6 @@ typedef struct GameState { // these must point entities in its own array. u64 current_roomid; - Entity *player; - Entity *world_entity; Entity entities[MAX_ENTITIES]; rnd_gamerand_t random; } GameState;