From 98d7dc146a9598009d3aeebbfb74c8838192759f Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Sat, 19 Nov 2022 18:14:20 -0800 Subject: [PATCH] Added blueprint palette and item toolbar --- gamestate.c | 186 ++++++++++++++++++++++++----------------------- main.c | 204 +++++++++++++++++++++++++++++++++++++++++++--------- types.h | 37 +++++++--- 3 files changed, 297 insertions(+), 130 deletions(-) diff --git a/gamestate.c b/gamestate.c index 64f0888..4370409 100644 --- a/gamestate.c +++ b/gamestate.c @@ -73,22 +73,29 @@ Entity *get_entity(GameState *gs, EntityID id) return to_return; } -static uint64_t box_unlock_number(enum BoxType box) +static BOX_UNLOCKS_TYPE box_unlock_number(enum BoxType box) { - assert((uint64_t)box < 64); - return (uint64_t)((uint64_t)1 << ((uint64_t)box)); + assert((BOX_UNLOCKS_TYPE)box < 64); + return (BOX_UNLOCKS_TYPE)((BOX_UNLOCKS_TYPE)1 << ((BOX_UNLOCKS_TYPE)box)); +} + +static bool learned_boxes_has_box(BOX_UNLOCKS_TYPE learned, enum BoxType box) +{ + return (learned & box_unlock_number(box)) > 0; } void unlock_box(Player *player, enum BoxType box) { assert(box < MAX_BOX_TYPES); + assert(box != BoxInvalid); player->box_unlocks |= box_unlock_number(box); } bool box_unlocked(Player *player, enum BoxType box) { assert(box < MAX_BOX_TYPES); - return (player->box_unlocks & box_unlock_number(box)) > 0; + if(box == BoxInvalid) return false; + return learned_boxes_has_box(player->box_unlocks, box); } EntityID get_id(GameState *gs, Entity *e) @@ -611,6 +618,8 @@ float entity_angular_velocity(Entity *grid) } Entity *box_grid(Entity *box) { + if(box == NULL) return NULL; + assert(box->is_box); return (Entity *)cpBodyGetUserData(cpShapeGetBody(box->shape)); } // in local space @@ -787,18 +796,6 @@ SerMaybeFailure ser_var(SerState *ser, char *var_pointer, size_t var_size, const enum GameVersion { VInitial, - VAddedTest, - VAddedSerToDisk, - VRemovedTest, - VChangedVectorSerializing, - VAddedLastUsedMedbay, - VAddedSquads, - VAddedSquadInvites, - VRemovedTimeFromDiskSave, // did this to avoid wayy too big a time causing precision problems - VReallyRemovedTimeFromDiskSave, // apparently last one didn't work - VRemovedInsideOfMe, - VSwitchedToUnlocks, - VAddedPlatonic, VMax, // this minus one will be the version used }; @@ -839,12 +836,9 @@ SerMaybeFailure ser_inputframe(SerState *ser, InputFrame *i) SER_VAR(&i->take_over_squad); SER_ASSERT(i->take_over_squad >= 0 || i->take_over_squad == -1); SER_ASSERT(i->take_over_squad < SquadLast); - if (ser->version >= VAddedSquadInvites) - { - SER_VAR(&i->accept_cur_squad_invite); - SER_VAR(&i->reject_cur_squad_invite); - SER_MAYBE_RETURN(ser_entityid(ser, &i->invite_this_player)); - } + SER_VAR(&i->accept_cur_squad_invite); + SER_VAR(&i->reject_cur_squad_invite); + SER_MAYBE_RETURN(ser_entityid(ser, &i->invite_this_player)); SER_VAR(&i->seat_action); SER_MAYBE_RETURN(ser_V2(ser, &i->hand_pos)); @@ -863,20 +857,11 @@ SerMaybeFailure ser_player(SerState *ser, Player *p) SER_VAR(&p->connected); if (p->connected) { - if (ser->version >= VSwitchedToUnlocks) - { - SER_VAR(&p->box_unlocks); - } - else - { - bool throwaway; - SER_VAR_NAME(&throwaway, "&p->unlocked_bombs"); - } - if (ser->version >= VAddedSquads) - SER_VAR(&p->squad); + SER_VAR(&p->box_unlocks); + + SER_VAR(&p->squad); SER_MAYBE_RETURN(ser_entityid(ser, &p->entity)); - if (ser->version >= VAddedLastUsedMedbay) - SER_MAYBE_RETURN(ser_entityid(ser, &p->last_used_medbay)); + SER_MAYBE_RETURN(ser_entityid(ser, &p->last_used_medbay)); SER_MAYBE_RETURN(ser_inputframe(ser, &p->input)); } @@ -889,10 +874,6 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e) SER_VAR(&e->generation); SER_VAR(&e->damage); - int test; - if (ser->version < VRemovedTest && ser->version >= VAddedTest) - SER_VAR(&test); - bool has_body = ser->serializing && e->body != NULL; SER_VAR(&has_body); @@ -922,14 +903,7 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e) V2 shape_pos; if (ser->serializing) shape_pos = entity_shape_pos(e); - if (ser->version < VChangedVectorSerializing) - { - SER_VAR(&shape_pos); - } - else - { - SER_MAYBE_RETURN(ser_V2(ser, &shape_pos)); - } + SER_MAYBE_RETURN(ser_V2(ser, &shape_pos)); float shape_mass; if (ser->serializing) @@ -958,10 +932,8 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e) SER_ASSERT(e->no_save_to_disk); SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box)); - if (ser->version >= VAddedSquads) - SER_VAR(&e->presenting_squad); - if (ser->version >= VAddedSquadInvites) - SER_VAR(&e->squad_invited_to); + SER_VAR(&e->presenting_squad); + SER_VAR(&e->squad_invited_to); SER_VAR(&e->goldness); } @@ -984,37 +956,39 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e) if (e->is_box) { SER_VAR(&e->box_type); + SER_VAR(&e->is_platonic); SER_VAR(&e->always_visible); - - if (ser->version >= VAddedPlatonic) - SER_VAR(&e->is_platonic); - - if (ser->version <= VSwitchedToUnlocks) - { - bool throwaway; - SER_VAR_NAME(&throwaway, "&e->is_explosion_unlock"); - } SER_MAYBE_RETURN(ser_entityid(ser, &e->next_box)); SER_MAYBE_RETURN(ser_entityid(ser, &e->prev_box)); SER_VAR(&e->compass_rotation); SER_VAR(&e->indestructible); - SER_VAR(&e->thrust); - SER_VAR(&e->wanted_thrust); - SER_VAR(&e->energy_used); - SER_VAR(&e->sun_amount); - if (ser->version >= VAddedPlatonic) + switch (e->box_type) { + case BoxMedbay: + case BoxCockpit: + if (!ser->save_or_load_from_disk) + SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me)); + break; + case BoxThruster: + SER_VAR(&e->thrust); + SER_VAR(&e->wanted_thrust); + break; + case BoxBattery: + SER_VAR(&e->energy_used); + break; + case BoxSolarPanel: + SER_VAR(&e->sun_amount); + break; + case BoxScanner: + SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_scanning)); + SER_VAR(&e->currently_scanning_progress); + SER_VAR(&e->blueprints_learned); SER_VAR(&e->scanner_head_rotate); SER_VAR(&e->platonic_nearest_direction); SER_VAR(&e->platonic_detection_strength); - } - - if (ser->version >= VRemovedInsideOfMe && ser->save_or_load_from_disk) - { - } - else - { - SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me)); + break; + default: + break; } } @@ -1094,13 +1068,7 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s) SER_ASSERT(cur_next_entity <= ser->max_entity_index); SER_VAR(&s->your_player); - if (ser->version >= VReallyRemovedTimeFromDiskSave && ser->save_or_load_from_disk) - { - } - else - { - SER_VAR(&gs->time); - } + SER_VAR(&gs->time); SER_MAYBE_RETURN(ser_V2(ser, &gs->goldpos)); @@ -1389,10 +1357,15 @@ bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, uns // has to be global var because can only get this information static THREADLOCAL cpShape *closest_to_point_in_radius_result = NULL; static THREADLOCAL float closest_to_point_in_radius_result_largest_dist = 0.0f; +static THREADLOCAL bool (*closest_to_point_in_radius_filter_func)(Entity *); static void closest_point_callback_func(cpShape *shape, cpContactPointSet *points, void *data) { assert(points->count == 1); - if (!cp_shape_entity(shape)->is_box) + Entity *e = cp_shape_entity(shape); + if (!e->is_box) + return; + + if (closest_to_point_in_radius_filter_func != NULL && !closest_to_point_in_radius_filter_func(e)) return; float dist = V2length(cp_to_v2(cpvsub(points->points[0].pointA, points->points[0].pointB))); // float dist = -points->points[0].distance; @@ -1403,11 +1376,13 @@ static void closest_point_callback_func(cpShape *shape, cpContactPointSet *point } } -Entity *closest_to_point_in_radius(GameState *gs, V2 point, float radius) +// filter func null means everything is ok, if it's not null and returns false, that means +// exclude it from the selection. This returns the closest box entity! +Entity *closest_box_to_point_in_radius(struct GameState *gs, V2 point, float radius, bool (*filter_func)(Entity *)) { closest_to_point_in_radius_result = NULL; closest_to_point_in_radius_result_largest_dist = 0.0f; - + closest_to_point_in_radius_filter_func = filter_func; cpBody *tmpbody = cpBodyNew(0.0f, 0.0f); cpShape *circle = cpCircleShapeNew(tmpbody, radius, v2_to_cp(point)); cpSpaceShapeQuery(gs->space, circle, closest_point_callback_func, NULL); @@ -1418,12 +1393,22 @@ Entity *closest_to_point_in_radius(GameState *gs, V2 point, float radius) if (closest_to_point_in_radius_result != NULL) { // @Robust query here for only boxes that are part of ships, could get nasty... - return cp_body_entity(cpShapeGetBody(closest_to_point_in_radius_result)); + return cp_shape_entity(closest_to_point_in_radius_result); } return NULL; } +static THREADLOCAL BOX_UNLOCKS_TYPE scanner_has_learned = 0; +static bool scanner_filter(Entity *e) +{ + if (!e->is_box) + return false; + if (learned_boxes_has_box(scanner_has_learned, e->box_type)) + return false; + return true; +} + static float cur_explosion_damage = 0.0f; static V2 explosion_origin = {0}; static void explosion_callback_func(cpShape *shape, cpContactPointSet *points, void *data) @@ -1474,7 +1459,7 @@ uint64_t tick(GameState *gs) Entity *grid_to_build_on(GameState *gs, V2 world_hand_pos) { - return closest_to_point_in_radius(gs, world_hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP); + return box_grid(closest_box_to_point_in_radius(gs, world_hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP, NULL)); } V2 potentially_snap_hand_pos(GameState *gs, V2 world_hand_pos) @@ -1561,7 +1546,7 @@ EntityID create_initial_world(GameState *gs) bool indestructible = false; Entity *grid = new_entity(gs); grid_create(gs, grid); - entity_set_pos(grid, (V2){-16.0f, 0.0f}); + entity_set_pos(grid, (V2){-5.0f, 0.0f}); entity_ensure_in_orbit(grid); Entity *explosion_box = new_entity(gs); box_create(gs, explosion_box, grid, (V2){0}); @@ -1796,7 +1781,7 @@ void process(GameState *gs, float dt) grid_remove_box(gs, cur_grid, cur_box); } } - else + else if(box_unlocked(player, player->input.build_type)) { // creating a box p->damage += DAMAGE_TO_PLAYER_PER_BLOCK; @@ -1821,6 +1806,7 @@ void process(GameState *gs, float dt) grid_correct_for_holes(gs, target_grid); // no holey ship for you! new_box->box_type = player->input.build_type; new_box->compass_rotation = player->input.build_rotation; + if(new_box->box_type == BoxScanner) new_box->blueprints_learned = player->box_unlocks; if (new_box->box_type == BoxBattery) new_box->energy_used = BATTERY_CAPACITY; } @@ -1954,7 +1940,7 @@ void process(GameState *gs, float dt) } if (cur_box->box_type == BoxScanner) { - // set the nearest platonic solid! + // set the nearest platonic solid! only on server as only the server sees everything if (gs->server_side_computing) { float energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, SCANNER_ENERGY_USE * dt); @@ -1993,6 +1979,30 @@ void process(GameState *gs, float dt) } } } + + // unlock the nearest platonic solid! + scanner_has_learned = cur_box->blueprints_learned; + Entity *to_learn = closest_box_to_point_in_radius(gs, entity_pos(cur_box), SCANNER_RADIUS, scanner_filter); + if(to_learn != NULL) + assert(to_learn->is_box); + EntityID new_id = get_id(gs, to_learn); + + if(!entityids_same(cur_box->currently_scanning, new_id)) + { + cur_box->currently_scanning_progress = 0.0f; + cur_box->currently_scanning = new_id; + } + + if(to_learn != NULL) + cur_box->currently_scanning_progress += dt*SCANNER_SCAN_RATE; + else + cur_box->currently_scanning_progress = 0.0f; + + if(cur_box->currently_scanning_progress >= 1.0f) + { + cur_box->blueprints_learned |= box_unlock_number(to_learn->box_type); + } + cur_box->scanner_head_rotate_speed = lerp(cur_box->scanner_head_rotate_speed, cur_box->platonic_detection_strength > 0.0f ? 3.0f : 0.0f, dt * 3.0f); cur_box->scanner_head_rotate += cur_box->scanner_head_rotate_speed * dt; cur_box->scanner_head_rotate = fmodf(cur_box->scanner_head_rotate, 2.0f * PI); diff --git a/main.c b/main.c index c7171a8..14831fd 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,8 @@ #include #include // starting server thread +#define TOOLBAR_SLOTS 9 + #pragma warning(disable : 33010) // this warning is so broken, doesn't // understand assert() #include "sokol_app.h" @@ -106,9 +108,11 @@ static sg_image image_check; static sg_image image_no; static sg_image image_solarpanel_charging; static sg_image image_scanner_head; +static sg_image image_itemswitch; -static int cur_editing_boxtype = -1; -static int cur_editing_rotation = 0; +static enum BoxType toolbar[TOOLBAR_SLOTS] = {BoxInvalid}; +static int cur_toolbar_slot = 0; +static int cur_editing_rotation = Right; // audio static bool muted = false; @@ -218,6 +222,13 @@ struct SquadMeta squad_meta(enum Squad squad) return (struct SquadMeta){0}; } +static enum BoxType currently_building() +{ + assert(cur_toolbar_slot >= 0); + assert(cur_toolbar_slot < TOOLBAR_SLOTS); + return toolbar[cur_toolbar_slot]; +} + struct BoxInfo boxinfo(enum BoxType type) { for (int i = 0; i < ARRLEN(boxes); i++) @@ -505,6 +516,7 @@ static void init(void) image_no = load_image("loaded/no.png"); image_solarpanel_charging = load_image("loaded/solarpanel_charging.png"); image_scanner_head = load_image("loaded/scanner_head.png"); + image_itemswitch = load_image("loaded/itemswitch.png"); } // socket initialization @@ -613,12 +625,6 @@ bool can_build(int i) return allow_building; } -void attempt_to_build(int i) -{ - if (can_build(i)) - cur_editing_boxtype = i; -} - static V2 screen_to_world(float width, float height, V2 screen) { V2 world = screen; @@ -651,6 +657,105 @@ static void ui(bool draw, float dt, float width, float height) if (draw) sgp_push_transform(); + // draw pick new box type menu + static bool picking_new_boxtype = false; + static float pick_opacity = 0.0f; + { + AABB pick_modal = (AABB){ + .x = width * 0.25f, + .y = height * 0.25f, + .width = width * 0.5f, + .height = height * 0.5f, + }; + pick_opacity = lerp(pick_opacity, picking_new_boxtype ? 1.0f : 0.0f, dt * 7.0f); + if (picking_new_boxtype) + { + if (build_pressed) + { + if (has_point(pick_modal, mouse_pos)) + { + } + else + { + build_pressed = false; + picking_new_boxtype = false; + } + } + } + static float item_scaling[ARRLEN(boxes)] = {1.0f}; + { + float alpha = pick_opacity * 0.8f; + if (draw) + { + sgp_set_color(0.4f, 0.4f, 0.4f, alpha); + sgp_draw_filled_rect(pick_modal.x, pick_modal.y, pick_modal.width, pick_modal.height); + + sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f * pick_opacity); + } + int boxes_per_row = (int)floorf(pick_modal.width / 128.0f); + float cell_width = pick_modal.width / (float)boxes_per_row; + float cell_height = cell_width; + float padding = 0.2f * cell_width; + int cur_row = 0; + int cur_column = 0; + for (int i = 0; i < ARRLEN(boxes); i++) + { + if (cur_column >= boxes_per_row) + { + cur_column = 0; + cur_row++; + } + float item_width = cell_width - padding * 2.0f; + float item_height = cell_height - padding * 2.0f; + + item_width *= item_scaling[i]; + item_height *= item_scaling[i]; + + float cell_y = pick_modal.y + (float)cur_row * cell_height; + float cell_x = pick_modal.x + (float)cur_column * cell_width; + float item_x = cell_x + (cell_width - item_width) / 2.0f; + float item_y = cell_y + (cell_height - item_height) / 2.0f; + + bool item_being_hovered = has_point((AABB){ + .x = item_x, + .y = item_y, + .width = item_width, + .height = item_height, + }, + mouse_pos); + + item_scaling[i] = lerp(item_scaling[i], item_being_hovered ? 1.3f : 1.0f, dt*4.0f); + + struct BoxInfo info = boxes[i]; + if(item_being_hovered && build_pressed) + { + toolbar[cur_toolbar_slot] = info.type; + build_pressed = false; + } + if (draw) + { + if (can_build(info.type)) + { + sgp_set_image(0, info.image); + } + else + { + sgp_set_image(0, image_mystery); + } + transform_scope + { + sgp_scale_at(1.0f, -1.0f, item_x + item_width / 2.0f, item_y + item_height / 2.0f); + pipeline_scope(goodpixel_pipeline) + sgp_draw_textured_rect(item_x, item_y, item_width, item_height); + sgp_reset_image(0); + } + } + + cur_column++; + } + } + } + // draw squad invite static float invite_y = -200.0f; static enum Squad draw_as_squad = SquadNone; @@ -978,7 +1083,7 @@ static void ui(bool draw, float dt, float width, float height) (float)sg_query_image_info(image_itemframe).width * 2.0f; float itemframe_height = (float)sg_query_image_info(image_itemframe).height * 2.0f; - float total_width = itemframe_width * (float)ARRLENF(boxes); + float total_width = itemframe_width * (float)TOOLBAR_SLOTS; float item_width = itemframe_width * 0.75f; float item_height = itemframe_height * 0.75f; float item_offset_x = (itemframe_width - item_width) / 2.0f; @@ -986,8 +1091,9 @@ static void ui(bool draw, float dt, float width, float height) float x = width / 2.0f - total_width / 2.0f; float y = height - itemframe_height * 1.5f; - for (int i = 0; i < ARRLEN(boxes); i++) + for (int i = 0; i < TOOLBAR_SLOTS; i++) { + // mouse over the item frame box if (has_point( (AABB){ .x = x, @@ -999,14 +1105,38 @@ static void ui(bool draw, float dt, float width, float height) build_pressed) { // "handle" mouse pressed - attempt_to_build(i); + cur_toolbar_slot = i; + build_pressed = false; + } + + // mouse over the item switch button + bool switch_hovered = false; + if (has_point( + (AABB){ + .x = x, + .y = y - 20.0f, + .width = itemframe_width, + .height = itemframe_height * 0.2f, + }, + mouse_pos)) + { + switch_hovered = true; + } + + if (switch_hovered && build_pressed) + { + picking_new_boxtype = true; build_pressed = false; } if (draw) { sgp_set_color(1.0f, 1.0f, 1.0f, cur_opacity); - if (cur_editing_boxtype == i) + + bool is_current = cur_toolbar_slot == i; + static float switch_scaling = 1.0f; + switch_scaling = lerp(switch_scaling, switch_hovered ? 1.8f : 1.2f, dt * 3.0f); + if (is_current) { sgp_set_image(0, image_itemframe_selected); } @@ -1016,26 +1146,36 @@ static void ui(bool draw, float dt, float width, float height) } pipeline_scope(goodpixel_pipeline) sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height); - struct BoxInfo info = boxinfo((enum BoxType)i); - if (can_build(i)) - { - sgp_set_image(0, info.image); - } - else - { - sgp_set_image(0, image_mystery); - } + sgp_reset_image(0); transform_scope { float item_x = x + item_offset_x; float item_y = y + item_offset_y; sgp_scale_at(1.0f, -1.0f, item_x + item_width / 2.0f, item_y + item_height / 2.0f); - // sgp_scale(1.0f, -1.0f); + pipeline_scope(goodpixel_pipeline) + { + if (toolbar[i] != BoxInvalid) + { + struct BoxInfo info = boxinfo(toolbar[i]); + sgp_set_image(0, info.image); sgp_draw_textured_rect(item_x, item_y, item_width, item_height); + + sgp_reset_image(0); + } + if (is_current) + { + sgp_set_image(0, image_itemswitch); + float switch_item_width = item_width * switch_scaling; + float switch_item_height = item_height * switch_scaling; + item_x -= (switch_item_width - item_width) / 2.0f; + item_y -= (switch_item_height - item_height) / 2.0f; + sgp_draw_textured_rect(item_x, item_y + 20.0f, switch_item_width, switch_item_height); + sgp_reset_image(0); + } + } } - sgp_reset_image(0); } x += itemframe_width; } @@ -1324,10 +1464,10 @@ static void frame(void) reject_invite = false; } - if (build_pressed && cur_editing_boxtype != -1) + if (build_pressed && currently_building() != BoxInvalid) { cur_input_frame.dobuild = build_pressed; - cur_input_frame.build_type = cur_editing_boxtype; + cur_input_frame.build_type = currently_building(); cur_input_frame.build_rotation = cur_editing_rotation; } @@ -1405,8 +1545,8 @@ static void frame(void) global_hand_pos = get_global_hand_pos(world_mouse_pos, &hand_at_arms_length); - Entity *placing_grid = closest_to_point_in_radius( - &gs, global_hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP); + Entity *placing_grid = box_grid(closest_box_to_point_in_radius( + &gs, global_hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP, NULL)); if (placing_grid == NULL) { build_preview = (struct BuildPreviewInfo){ @@ -1530,14 +1670,14 @@ static void frame(void) } // building preview - if (cur_editing_boxtype != -1) + if (currently_building() != BoxInvalid) { sgp_set_color(0.5f, 0.5f, 0.5f, (sinf((float)time * 9.0f) + 1.0f) / 3.0f + 0.2f); transform_scope { - sgp_set_image(0, boxinfo(cur_editing_boxtype).image); + sgp_set_image(0, boxinfo(currently_building()).image); sgp_rotate_at(build_preview.grid_rotation + rotangle(cur_editing_rotation), global_hand_pos.x, global_hand_pos.y); @@ -1785,10 +1925,10 @@ void event(const sapp_event *e) fullscreened = false; } int key_num = e->key_code - SAPP_KEYCODE_0; - int target_box = key_num - 1; - if (target_box < BoxLast && target_box >= 0) + int target_slot = key_num - 1; + if (target_slot <= TOOLBAR_SLOTS && target_slot >= 0) { - attempt_to_build(target_box); + cur_toolbar_slot = target_slot; } if (!mouse_frozen) diff --git a/types.h b/types.h index 254026a..c82eeb6 100644 --- a/types.h +++ b/types.h @@ -13,6 +13,8 @@ #define PLAYER_JETPACK_SPICE_PER_SECOND 0.1f #define SCANNER_ENERGY_USE 0.05f #define MAX_HAND_REACH 1.0f +#define SCANNER_SCAN_RATE 1.0f +#define SCANNER_RADIUS 1.0f #define GOLD_COLLECT_RADIUS 0.3f #define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f #define BOX_MASS 1.0f @@ -60,6 +62,9 @@ #define LOCAL_INPUT_QUEUE_MAX 90 // please god let you not have more than 90 frames of game latency #define INPUT_QUEUE_MAX 15 +// fucks up serialization if you change this, fix it if you do that! +#define BOX_UNLOCKS_TYPE uint64_t + // cross platform threadlocal variables #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) #define THREADLOCAL __declspec(thread) @@ -130,6 +135,7 @@ typedef sgp_point P2; enum BoxType { + BoxInvalid, // zero initialized box is invalid! BoxHullpiece, BoxThruster, BoxBattery, @@ -231,32 +237,42 @@ typedef struct Entity // boxes bool is_box; - bool is_platonic; // can't be destroyed, unaffected by physical forces - bool always_visible; // always serialized to the player - - enum BoxType box_type; - EntityID next_box; + bool is_platonic; // can't be destroyed, unaffected by physical forces + bool always_visible; // always serialized to the player. @Robust check if not used + EntityID next_box; // for the grid! EntityID prev_box; // doubly linked so can remove in middle of chain enum CompassRotation compass_rotation; bool indestructible; + + // used by medbay and cockpit + EntityID player_who_is_inside_of_me; + + // only serialized when box_type is thruster float wanted_thrust; // the thrust command applied to the thruster float thrust; // the actual thrust it can provide based on energy sources in the grid + + // only serialized when box_type is battery float energy_used; // battery, between 0 battery capacity. You have to look through code to figure out what that is! haha sucker! + + // only serialized when box_type is solar panel float sun_amount; // solar panel, between 0 and 1 - EntityID player_who_is_inside_of_me; - // only updated when it's a scanner + // scanner only stuff! + EntityID currently_scanning; + float currently_scanning_progress; // when 1.0, scans it! + BOX_UNLOCKS_TYPE blueprints_learned; // @Robust make this same type as blueprints float scanner_head_rotate_speed; // not serialized, cosmetic float scanner_head_rotate; V2 platonic_nearest_direction; // normalized float platonic_detection_strength; // from zero to one } Entity; + typedef struct Player { bool connected; - uint64_t box_unlocks; // each bit is that box's unlock + BOX_UNLOCKS_TYPE box_unlocks; // each bit is that box's unlock enum Squad squad; EntityID entity; EntityID last_used_medbay; @@ -267,7 +283,7 @@ typedef struct GameState { cpSpace *space; - double time; // @Robust separate tick integer not prone to precision issues + double time; // @Robust separate tick integer not prone to precision issues. Could be very large as is saved to disk! V2 goldpos; @@ -351,7 +367,7 @@ void initialize(struct GameState *gs, void *entity_arena, size_t entity_arena_si void destroy(struct GameState *gs); void process_fixed_timestep(GameState *gs); void process(struct GameState *gs, float dt); // does in place -Entity *closest_to_point_in_radius(struct GameState *gs, V2 point, float radius); +Entity *closest_box_to_point_in_radius(struct GameState *gs, V2 point, float radius, bool(*filter_func)(Entity*)); uint64_t tick(struct GameState *gs); // all of these return if successful or not @@ -376,6 +392,7 @@ void entity_destroy(GameState *gs, Entity *e); // grid void grid_create(struct GameState *gs, Entity *e); void box_create(struct GameState *gs, Entity *new_box, Entity *grid, V2 pos); +Entity *box_grid(Entity *box); V2 grid_com(Entity *grid); V2 grid_vel(Entity *grid); V2 box_vel(Entity *box);