Energy use refactor, feedback on not enough energy

main
Cameron Murphy Reikes 2 years ago
parent ea78de0165
commit aee534480f

@ -19,7 +19,7 @@
// #define DEBUG_WORLD // #define DEBUG_WORLD
#define UNLOCK_ALL #define UNLOCK_ALL
#define TIME_BETWEEN_WORLD_SAVE 1000000.0f #define TIME_BETWEEN_WORLD_SAVE 1000000.0f
#define INFINITE_RESOURCES // #define INFINITE_RESOURCES
#define DEBUG_TOOLS #define DEBUG_TOOLS
#define CHIPMUNK_INTEGRITY_CHECK #define CHIPMUNK_INTEGRITY_CHECK
// #define FAT_THRUSTERS // #define FAT_THRUSTERS

@ -1205,6 +1205,7 @@ SerMaybeFailure ser_fV2(SerState *ser, cpVect *var)
SerMaybeFailure ser_f(SerState *ser, double *d) SerMaybeFailure ser_f(SerState *ser, double *d)
{ {
float f; float f;
if (ser->serializing) if (ser->serializing)
f = (float)*d; f = (float)*d;
@ -1212,6 +1213,16 @@ SerMaybeFailure ser_f(SerState *ser, double *d)
SER_ASSERT(!isnan(f)); SER_ASSERT(!isnan(f));
*d = f; *d = f;
return ser_ok; return ser_ok;
// if you're ever sketched out by floating point precision you can use this to test...
/* double f;
if (ser->serializing)
f = (double)*d;
SER_VAR(&f);
SER_ASSERT(!isnan(f));
*d = f;
return ser_ok;*/
} }
SerMaybeFailure ser_bodydata(SerState *ser, struct BodyData *data) SerMaybeFailure ser_bodydata(SerState *ser, struct BodyData *data)
@ -1410,6 +1421,9 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me)); SER_MAYBE_RETURN(ser_entityid(ser, &e->player_who_is_inside_of_me));
break; break;
case BoxThruster: case BoxThruster:
SER_MAYBE_RETURN(ser_f(ser, &e->thrust));
SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust));
break;
case BoxGyroscope: case BoxGyroscope:
SER_MAYBE_RETURN(ser_f(ser, &e->thrust)); SER_MAYBE_RETURN(ser_f(ser, &e->thrust));
SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust)); SER_MAYBE_RETURN(ser_f(ser, &e->wanted_thrust));
@ -2022,9 +2036,14 @@ bool batteries_have_capacity_for(GameState *gs, Entity *grid, double *energy_lef
return false; return false;
} }
// returns any energy unable to burn // returns any effectiveness
double batteries_use_energy(GameState *gs, Entity *grid, double *energy_left_over, double energy_to_use) double batteries_use_energy(GameState *gs, Entity *grid, double *energy_left_over, double energy_to_use)
{ {
if (energy_to_use == 0.0)
{
return 1.0;
}
double energy_wanting_to_use = energy_to_use;
if (*energy_left_over > 0.0) if (*energy_left_over > 0.0)
{ {
double energy_to_use_from_leftover = fmin(*energy_left_over, energy_to_use); double energy_to_use_from_leftover = fmin(*energy_left_over, energy_to_use);
@ -2040,10 +2059,13 @@ double batteries_use_energy(GameState *gs, Entity *grid, double *energy_left_ove
battery->energy_used += energy_to_burn_from_this_battery; battery->energy_used += energy_to_burn_from_this_battery;
energy_to_use -= energy_to_burn_from_this_battery; energy_to_use -= energy_to_burn_from_this_battery;
if (energy_to_use <= 0.0) if (energy_to_use <= 0.0)
return 0.0; return 1.0;
} }
} }
return energy_to_use; double to_return = 1.0 - (energy_to_use / energy_wanting_to_use);
flight_assert(to_return >= 0.0);
flight_assert(to_return <= 1.0);
return to_return;
} }
double sun_dist_no_gravity(Entity *sun) double sun_dist_no_gravity(Entity *sun)
@ -2833,9 +2855,11 @@ void process(struct GameState *gs, double dt)
double new_sun = clamp01(fabs(cpvdot(box_facing_vector(cur_box), cpvnormalize(cpvsub(entity_pos(i.sun), entity_pos(cur_box)))))); double new_sun = clamp01(fabs(cpvdot(box_facing_vector(cur_box), cpvnormalize(cpvsub(entity_pos(i.sun), entity_pos(cur_box))))));
// less sun the farther away you are! // less sun the farther away you are!
new_sun *= lerp(1.0, 0.0, clamp01(cpvlength(cpvsub(entity_pos(cur_box), entity_pos(i.sun))) / sun_dist_no_gravity(i.sun))); new_sun *= lerp(1.0, 0.0, clamp01(cpvdist(entity_pos(cur_box), entity_pos(i.sun)) / sun_dist_no_gravity(i.sun)));
cur_box->sun_amount += new_sun; cur_box->sun_amount += new_sun;
} }
cur_box->sun_amount = clamp01(cur_box->sun_amount);
energy_to_add += cur_box->sun_amount * SOLAR_ENERGY_PER_SECOND * dt; energy_to_add += cur_box->sun_amount * SOLAR_ENERGY_PER_SECOND * dt;
} }
} }
@ -2854,7 +2878,7 @@ void process(struct GameState *gs, double dt)
flight_assert(energy_to_add >= 0.0); flight_assert(energy_to_add >= 0.0);
} }
// any energy_to_add existing now can also be used to power thrusters/medbay // any energy_to_add existing now can also be used to power thrusters/medbay. Kind of like a temporary separate battery
double non_battery_energy_left_over = energy_to_add; double non_battery_energy_left_over = energy_to_add;
// use the energy, stored in the batteries, in various boxes // use the energy, stored in the batteries, in various boxes
@ -2862,25 +2886,17 @@ void process(struct GameState *gs, double dt)
{ {
if (cur_box->box_type == BoxThruster) if (cur_box->box_type == BoxThruster)
{ {
cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, cur_box->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt);
double energy_to_consume = cur_box->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt; cur_box->thrust = cur_box->energy_effectiveness * cur_box->wanted_thrust;
if (cur_box->wanted_thrust == 0.0) if (cur_box->thrust >= 0.0)
{ cpBodyApplyForceAtWorldPoint(grid->body, (thruster_force(cur_box)), (entity_pos(cur_box)));
cur_box->thrust = 0.0;
}
if (energy_to_consume > 0.0)
{
cur_box->thrust = 0.0;
double energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, energy_to_consume);
cur_box->thrust = (1.0 - energy_unconsumed / energy_to_consume) * cur_box->wanted_thrust;
if (cur_box->thrust >= 0.0)
cpBodyApplyForceAtWorldPoint(grid->body, (thruster_force(cur_box)), (entity_pos(cur_box)));
}
} }
if (cur_box->box_type == BoxGyroscope) if (cur_box->box_type == BoxGyroscope)
{ {
cur_box->gyrospin_velocity = lerp(cur_box->gyrospin_velocity, cur_box->thrust * 20.0, dt * 5.0); cur_box->gyrospin_velocity = lerp(cur_box->gyrospin_velocity, cur_box->thrust * 20.0, dt * 5.0);
cur_box->gyrospin_angle += cur_box->gyrospin_velocity * dt; cur_box->gyrospin_angle += cur_box->gyrospin_velocity * dt;
// wrap to keep the number small
if (cur_box->gyrospin_angle > 2.0 * PI) if (cur_box->gyrospin_angle > 2.0 * PI)
{ {
cur_box->gyrospin_angle -= 2.0 * PI; cur_box->gyrospin_angle -= 2.0 * PI;
@ -2889,6 +2905,7 @@ void process(struct GameState *gs, double dt)
{ {
cur_box->gyrospin_angle += 2.0 * PI; cur_box->gyrospin_angle += 2.0 * PI;
} }
if (cur_box->wanted_thrust == 0.0) if (cur_box->wanted_thrust == 0.0)
{ {
cur_box->thrust = 0.0; cur_box->thrust = 0.0;
@ -2896,39 +2913,27 @@ void process(struct GameState *gs, double dt)
double thrust_to_want = cur_box->wanted_thrust; double thrust_to_want = cur_box->wanted_thrust;
if (cur_box->wanted_thrust == 0.0) if (cur_box->wanted_thrust == 0.0)
thrust_to_want = clamp(-cpBodyGetAngularVelocity(grid->body) * GYROSCOPE_PROPORTIONAL_INERTIAL_RESPONSE, -1.0, 1.0); thrust_to_want = clamp(-cpBodyGetAngularVelocity(grid->body) * GYROSCOPE_PROPORTIONAL_INERTIAL_RESPONSE, -1.0, 1.0);
double energy_to_consume = fabs(thrust_to_want * GYROSCOPE_ENERGY_USED_PER_SECOND * dt); cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, fabs(thrust_to_want * GYROSCOPE_ENERGY_USED_PER_SECOND * dt));
if (energy_to_consume > 0.0) cur_box->thrust = cur_box->energy_effectiveness * thrust_to_want;
{ if (fabs(cur_box->thrust) >= 0.0)
cur_box->thrust = 0.0; cpBodySetTorque(grid->body, cpBodyGetTorque(grid->body) + cur_box->thrust * GYROSCOPE_TORQUE);
double energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, energy_to_consume);
cur_box->thrust = (1.0 - energy_unconsumed / energy_to_consume) * thrust_to_want;
if (fabs(cur_box->thrust) >= 0.0)
cpBodySetTorque(grid->body, cpBodyGetTorque(grid->body) + cur_box->thrust * GYROSCOPE_TORQUE);
}
} }
if (cur_box->box_type == BoxMedbay) if (cur_box->box_type == BoxMedbay)
{ {
Entity *potential_meatbag_to_heal = get_entity(gs, cur_box->player_who_is_inside_of_me); Entity *potential_meatbag_to_heal = get_entity(gs, cur_box->player_who_is_inside_of_me);
if (potential_meatbag_to_heal != NULL) if (potential_meatbag_to_heal != NULL)
{ {
double wanted_energy_use = fmin(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt); double wanted_energy_to_heal = fmin(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt);
if (wanted_energy_use > 0.0) cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, wanted_energy_to_heal);
{ potential_meatbag_to_heal->damage -= wanted_energy_to_heal * cur_box->energy_effectiveness;
double energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, wanted_energy_use);
potential_meatbag_to_heal->damage -= (1.0 - energy_unconsumed / wanted_energy_use) * wanted_energy_use;
}
} }
} }
if (cur_box->box_type == BoxCloaking) if (cur_box->box_type == BoxCloaking)
{ {
double energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, CLOAKING_ENERGY_USE * dt); cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, CLOAKING_ENERGY_USE * dt);
if (energy_unconsumed >= CLOAKING_ENERGY_USE * dt) cur_box->cloaking_power = lerp(cur_box->cloaking_power, cur_box->energy_effectiveness, dt * 3.0);
if (cur_box->energy_effectiveness >= 1.0)
{ {
cur_box->cloaking_power = lerp(cur_box->cloaking_power, 0.0, dt * 3.0);
}
else
{
cur_box->cloaking_power = lerp(cur_box->cloaking_power, 1.0, dt * 3.0);
rect_query(gs->space, (BoxCentered){ rect_query(gs->space, (BoxCentered){
.pos = entity_pos(cur_box), .pos = entity_pos(cur_box),
.rotation = entity_rotation(cur_box), .rotation = entity_rotation(cur_box),
@ -2940,7 +2945,6 @@ void process(struct GameState *gs, double dt)
{ {
cpShape *shape = res->shape; cpShape *shape = res->shape;
Entity *from_cloaking_box = cur_box; Entity *from_cloaking_box = cur_box;
GameState *gs = entitys_gamestate(from_cloaking_box);
Entity *to_cloak = cp_shape_entity(shape); Entity *to_cloak = cp_shape_entity(shape);
to_cloak->time_was_last_cloaked = elapsed_time(gs); to_cloak->time_was_last_cloaked = elapsed_time(gs);
@ -2955,8 +2959,9 @@ void process(struct GameState *gs, double dt)
if (cur_box->missile_construction_charge < 1.0) if (cur_box->missile_construction_charge < 1.0)
{ {
double want_use_energy = dt * MISSILE_CHARGE_RATE; double want_use_energy = dt * MISSILE_CHARGE_RATE;
double energy_charged = want_use_energy - batteries_use_energy(gs, grid, &non_battery_energy_left_over, want_use_energy); cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, want_use_energy);
cur_box->missile_construction_charge += energy_charged;
cur_box->missile_construction_charge += cur_box->energy_effectiveness * want_use_energy;
} }
if (target.target_found && cur_box->missile_construction_charge >= 1.0) if (target.target_found && cur_box->missile_construction_charge >= 1.0)
@ -2972,11 +2977,12 @@ void process(struct GameState *gs, double dt)
} }
if (cur_box->box_type == BoxScanner) if (cur_box->box_type == BoxScanner)
{ {
// set the nearest platonic solid! only on server as only the server sees everything cur_box->energy_effectiveness = batteries_use_energy(gs, grid, &non_battery_energy_left_over, SCANNER_ENERGY_USE * dt);
// only the server knows all the positions of all the solids
if (gs->server_side_computing) if (gs->server_side_computing)
{ {
double energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, SCANNER_ENERGY_USE * dt); if (cur_box->energy_effectiveness < 1.0)
if (energy_unconsumed >= SCANNER_ENERGY_USE * dt)
{ {
cur_box->platonic_detection_strength = 0.0; cur_box->platonic_detection_strength = 0.0;
cur_box->platonic_nearest_direction = (cpVect){0}; cur_box->platonic_nearest_direction = (cpVect){0};

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

@ -125,6 +125,7 @@ static sg_image image_rightclick;
static sg_image image_rothelp; static sg_image image_rothelp;
static sg_image image_zoomeasyhelp; static sg_image image_zoomeasyhelp;
static sg_image image_gyrospin; static sg_image image_gyrospin;
static sg_image image_noenergy;
static enum BoxType toolbar[TOOLBAR_SLOTS] = { static enum BoxType toolbar[TOOLBAR_SLOTS] = {
BoxHullpiece, BoxHullpiece,
@ -652,6 +653,7 @@ static void init(void)
image_rothelp = load_image("loaded/rothelp.png"); image_rothelp = load_image("loaded/rothelp.png");
image_gyrospin = load_image("loaded/gyroscope_spinner.png"); image_gyrospin = load_image("loaded/gyroscope_spinner.png");
image_zoomeasyhelp = load_image("loaded/zoomeasyhelp.png"); image_zoomeasyhelp = load_image("loaded/zoomeasyhelp.png");
image_noenergy = load_image("loaded/no_energy.png");
} }
// socket initialization // socket initialization
@ -2029,6 +2031,7 @@ static void frame(void)
if (e->is_grid) if (e->is_grid)
{ {
Entity *g = e; Entity *g = e;
// draw boxes
BOXES_ITER(&gs, b, g) BOXES_ITER(&gs, b, g)
{ {
set_color_values(1.0, 1.0, 1.0, 1.0); set_color_values(1.0, 1.0, 1.0, 1.0);
@ -2193,6 +2196,27 @@ static void frame(void)
} }
// outside of the transform scope // outside of the transform scope
// if not enough energy for box to be used
bool uses_energy = false;
uses_energy |= b->box_type == BoxThruster;
uses_energy |= b->box_type == BoxGyroscope;
uses_energy |= b->box_type == BoxMedbay && get_entity(&gs, b->player_who_is_inside_of_me) != NULL;
uses_energy |= b->box_type == BoxCloaking;
uses_energy |= b->box_type == BoxMissileLauncher;
uses_energy |= b->box_type == BoxScanner;
if (uses_energy)
{
set_color_values(1.0, 1.0, 1.0, 1.0 - b->energy_effectiveness);
sgp_set_image(0, image_noenergy);
pipeline_scope(goodpixel_pipeline)
{
draw_texture_centered(cpvadd(entity_pos(b), cpv(0, -BOX_SIZE / 2.0)), 0.2);
}
sgp_reset_image(0);
}
if (b->box_type == BoxScanner) if (b->box_type == BoxScanner)
{ {
if (b->platonic_detection_strength > 0.0) if (b->platonic_detection_strength > 0.0)

@ -302,6 +302,11 @@ typedef struct Entity
enum CompassRotation compass_rotation; enum CompassRotation compass_rotation;
bool indestructible; bool indestructible;
// used by multiple boxes that use power to see if it should show low power warning.
// not serialized, populated during client side prediction. For the medbay
// is only valid if the medbay has somebody inside of it
double energy_effectiveness; // from 0 to 1, how effectively the box is operating given available power
// merger // merger
bool wants_disconnect; // don't serialized, termporary value not used across frames bool wants_disconnect; // don't serialized, termporary value not used across frames
@ -311,6 +316,7 @@ typedef struct Entity
// used by medbay and cockpit // used by medbay and cockpit
EntityID player_who_is_inside_of_me; EntityID player_who_is_inside_of_me;
// only serialized when box_type is thruster or gyroscope, used for both. Thrust // only serialized when box_type is thruster or gyroscope, used for both. Thrust
// can mean rotation thrust! // can mean rotation thrust!
double wanted_thrust; // the thrust command applied to the thruster double wanted_thrust; // the thrust command applied to the thruster

Loading…
Cancel
Save