Squad selection

main
Cameron Murphy Reikes 2 years ago
parent bacc6e9f03
commit fe2c9d07c5

@ -235,6 +235,7 @@
<ClCompile Include="thirdparty\minilzo\minilzo.c" /> <ClCompile Include="thirdparty\minilzo\minilzo.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="hueshift.gen.h" />
<ClInclude Include="ipsettings.h" /> <ClInclude Include="ipsettings.h" />
<ClInclude Include="thirdparty\minilzo\lzoconf.h" /> <ClInclude Include="thirdparty\minilzo\lzoconf.h" />
<ClInclude Include="thirdparty\minilzo\lzodefs.h" /> <ClInclude Include="thirdparty\minilzo\lzodefs.h" />

@ -191,6 +191,9 @@
<ClInclude Include="thirdparty\minilzo\minilzo.h"> <ClInclude Include="thirdparty\minilzo\minilzo.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="hueshift.gen.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="thirdparty\enet\enet_dll.cbp" /> <None Include="thirdparty\enet\enet_dll.cbp" />

@ -1,2 +1,3 @@
call shadergen.bat
set compileopts=/Fe"flight_debug" /Zi /FS /Fd"flight.pdb" /DSERVER_ADDRESS="\"127.0.0.1\"" /DDEBUG_RENDERING set compileopts=/Fe"flight_debug" /Zi /FS /Fd"flight.pdb" /DSERVER_ADDRESS="\"127.0.0.1\"" /DDEBUG_RENDERING
call build_msvc.bat call build_msvc.bat

@ -2,16 +2,12 @@
@REM what all the compile flags mean: https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 @REM what all the compile flags mean: https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
WHERE sokol-shdc.exe
IF %ERRORLEVEL% NEQ 0 ECHO ERROR download sokol-shdc from https://github.com/floooh/sokol-tools-bin/blob/master/bin/win32/sokol-shdc.exe and put it in this folder
set OPUSLIB=%~dp0\thirdparty\opus\win32\VS2015\x64\Release\opus.lib set OPUSLIB=%~dp0\thirdparty\opus\win32\VS2015\x64\Release\opus.lib
WHERE %OPUSLIB% WHERE %OPUSLIB%
IF %ERRORLEVEL% NEQ 0 ECHO ERROR Couldn't find %OPUSLIB% compile opus by opening the visual studio project in win32\VS2015 and building the release setting IF %ERRORLEVEL% NEQ 0 ECHO ERROR Couldn't find %OPUSLIB% compile opus by opening the visual studio project in win32\VS2015 and building the release setting
@REM example of how to compile shaders: sokol-shdc.exe --input triangle.glsl --output triangle.gen.h --slang glsl330:hlsl5:metal_macos
setlocal enabledelayedexpansion enableextensions setlocal enabledelayedexpansion enableextensions
pushd thirdparty\Chipmunk2D\src pushd thirdparty\Chipmunk2D\src
set MUNKSRC= set MUNKSRC=

File diff suppressed because it is too large Load Diff

@ -770,6 +770,7 @@ enum GameVersion
VRemovedTest, VRemovedTest,
VChangedVectorSerializing, VChangedVectorSerializing,
VAddedLastUsedMedbay, VAddedLastUsedMedbay,
VAddedSquads,
VMax, // this minus one will be the version used VMax, // this minus one will be the version used
}; };
@ -808,6 +809,7 @@ SerMaybeFailure ser_inputframe(SerState* ser, InputFrame* i)
SER_VAR(&i->tick); SER_VAR(&i->tick);
SER_VAR(&i->id); SER_VAR(&i->id);
SER_MAYBE_RETURN(ser_V2(ser, &i->movement)); SER_MAYBE_RETURN(ser_V2(ser, &i->movement));
SER_VAR(&i->take_over_squad);
SER_VAR(&i->seat_action); SER_VAR(&i->seat_action);
SER_MAYBE_RETURN(ser_entityid(ser, &i->seat_to_inhabit)); SER_MAYBE_RETURN(ser_entityid(ser, &i->seat_to_inhabit));
@ -829,6 +831,8 @@ SerMaybeFailure ser_player(SerState* ser, Player* p)
if (p->connected) if (p->connected)
{ {
SER_VAR(&p->unlocked_bombs); SER_VAR(&p->unlocked_bombs);
if(ser->version >= VAddedSquads)
SER_VAR(&p->squad);
SER_MAYBE_RETURN(ser_entityid(ser, &p->entity)); SER_MAYBE_RETURN(ser_entityid(ser, &p->entity));
if (ser->version >= VAddedLastUsedMedbay) if (ser->version >= VAddedLastUsedMedbay)
SER_MAYBE_RETURN(ser_entityid(ser, &p->last_used_medbay)); SER_MAYBE_RETURN(ser_entityid(ser, &p->last_used_medbay));
@ -912,6 +916,8 @@ SerMaybeFailure ser_entity(SerState* ser, GameState* gs, Entity* e)
{ {
SER_ASSERT(e->no_save_to_disk); SER_ASSERT(e->no_save_to_disk);
SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box)); SER_MAYBE_RETURN(ser_entityid(ser, &e->currently_inside_of_box));
if(ser->version >= VAddedSquads)
SER_VAR(&e->presenting_squad);
SER_VAR(&e->goldness); SER_VAR(&e->goldness);
} }
@ -1468,6 +1474,27 @@ void process(GameState* gs, float dt)
// process input // process input
PLAYERS_ITER(gs->players, player) PLAYERS_ITER(gs->players, player)
{ {
if (player->input.take_over_squad >= 0)
{
if (player->input.take_over_squad == SquadNone)
{
player->squad = SquadNone;
}
else {
bool squad_taken = false;
PLAYERS_ITER(gs->players, other_player)
{
if (other_player->squad == player->input.take_over_squad)
{
squad_taken = true;
break;
}
}
if (!squad_taken)
player->squad = player->input.take_over_squad;
}
player->input.take_over_squad = -1;
}
Entity* p = get_entity(gs, player->entity); Entity* p = get_entity(gs, player->entity);
if (p == NULL) if (p == NULL)
{ {
@ -1482,6 +1509,7 @@ void process(GameState* gs, float dt)
entity_ensure_in_orbit(p); entity_ensure_in_orbit(p);
} }
assert(p->is_player); assert(p->is_player);
p->presenting_squad = player->squad;
#ifdef INFINITE_RESOURCES #ifdef INFINITE_RESOURCES
p->damage = 0.0f; p->damage = 0.0f;

@ -0,0 +1,53 @@
@module hueshift
@vs vs
in vec4 coord;
out vec2 texUV;
void main() {
gl_Position = vec4(coord.xy, 0.0, 1.0);
texUV = coord.zw;
}
@end
@fs fs
uniform sampler2D iChannel0;
uniform uniforms {
int is_colorless; // if greater than zero, no color
float target_hue;
};
in vec2 texUV;
out vec4 fragColor;
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
vec4 outColor = texture(iChannel0, texUV);
vec3 hsv = rgb2hsv(outColor.rgb);
if(is_colorless > 0)
{
hsv.y = 0.0f;
} else if(hsv.y > 0.5) {
hsv.x = target_hue;
}
fragColor = vec4(hsv2rgb(hsv), outColor.a);
}
@end
@program program vs fs

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

443
main.c

@ -29,11 +29,16 @@
#define MINIAUDIO_IMPLEMENTATION #define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h" #include "miniaudio.h"
// shaders
#include "hueshift.gen.h"
static sg_pipeline pip;
static struct GameState gs = {0}; static struct GameState gs = {0};
static int myplayer = -1; static int myplayer = -1;
static bool right_mouse_down = false; static bool right_mouse_down = false;
static bool keydown[SAPP_KEYCODE_MENU] = {0}; static bool keydown[SAPP_KEYCODE_MENU] = {0};
typedef struct KeyPressed { typedef struct KeyPressed
{
bool pressed; bool pressed;
uint64_t frame; uint64_t frame;
} KeyPressed; } KeyPressed;
@ -50,6 +55,9 @@ static ENetHost* client;
static ENetPeer *peer; static ENetPeer *peer;
static float zoom_target = 300.0f; static float zoom_target = 300.0f;
static float zoom = 300.0f; static float zoom = 300.0f;
static enum Squad take_over_squad = (enum Squad) - 1; // -1 means not taking over any squad
// images
static sg_image image_itemframe; static sg_image image_itemframe;
static sg_image image_itemframe_selected; static sg_image image_itemframe_selected;
static sg_image image_thrusterburn; static sg_image image_thrusterburn;
@ -63,6 +71,9 @@ static sg_image image_mystery;
static sg_image image_explosion; static sg_image image_explosion;
static sg_image image_low_health; static sg_image image_low_health;
static sg_image image_mic_muted; static sg_image image_mic_muted;
static sg_image image_flag_available;
static sg_image image_flag_taken;
static int cur_editing_boxtype = -1; static int cur_editing_boxtype = -1;
static int cur_editing_rotation = 0; static int cur_editing_rotation = 0;
@ -81,7 +92,8 @@ ma_mutex play_packets_mutex = { 0 };
void *server_thread_handle = 0; void *server_thread_handle = 0;
ServerThreadInfo server_info = {0}; ServerThreadInfo server_info = {0};
static struct BoxInfo { static struct BoxInfo
{
enum BoxType type; enum BoxType type;
const char *image_path; const char *image_path;
sg_image image; sg_image image;
@ -118,12 +130,52 @@ static struct BoxInfo {
.needs_tobe_unlocked = true, .needs_tobe_unlocked = true,
}, },
}; };
const int boxes_len = sizeof(boxes) / sizeof(*boxes); #define ARRLEN(arr) (sizeof(arr) / sizeof(*arr))
static struct SquadMeta
{
enum Squad squad;
float hue;
bool is_colorless;
} squad_metas[] = {
{
.squad = SquadNone,
.is_colorless = true,
},
{
.squad = SquadRed,
.hue = 21.0f / 360.0f,
},
{
.squad = SquadGreen,
.hue = 111.0f / 360.0f,
},
{
.squad = SquadBlue,
.hue = 201.0f / 360.0f,
},
{
.squad = SquadPurple,
.hue = 291.0f / 360.0f,
},
};
struct SquadMeta squad_meta(enum Squad squad)
{
for (int i = 0; i < ARRLEN(squad_metas); i++)
{
if (squad_metas[i].squad == squad)
return squad_metas[i];
}
Log("Could not find squad %d!\n", squad);
return (struct SquadMeta){0};
}
struct BoxInfo struct BoxInfo
boxinfo(enum BoxType type) boxinfo(enum BoxType type)
{ {
for (int i = 0; i < boxes_len; i++) { for (int i = 0; i < ARRLEN(boxes); i++)
{
if (boxes[i].type == type) if (boxes[i].type == type)
return boxes[i]; return boxes[i];
} }
@ -142,7 +194,8 @@ load_image(const char* path)
const int desired_channels = 4; const int desired_channels = 4;
stbi_set_flip_vertically_on_load(true); stbi_set_flip_vertically_on_load(true);
stbi_uc *image_data = stbi_load(path, &x, &y, &comp, desired_channels); stbi_uc *image_data = stbi_load(path, &x, &y, &comp, desired_channels);
if (!image_data) { if (!image_data)
{
fprintf(stderr, "Failed to load image: %s\n", stbi_failure_reason()); fprintf(stderr, "Failed to load image: %s\n", stbi_failure_reason());
exit(-1); exit(-1);
} }
@ -203,6 +256,7 @@ void speaker_data_callback(ma_device* pDevice, void* pOutput, const void* pInput
static void static void
init(void) init(void)
{ {
// audio // audio
{ {
// opus // opus
@ -214,7 +268,6 @@ init(void)
assert(error == OPUS_OK); assert(error == OPUS_OK);
} }
ma_device_config microphone_config = ma_device_config_init(ma_device_type_capture); ma_device_config microphone_config = ma_device_config_init(ma_device_type_capture);
microphone_config.capture.format = ma_format_s16; microphone_config.capture.format = ma_format_s16;
@ -231,7 +284,8 @@ init(void)
ma_result result; ma_result result;
result = ma_device_init(NULL, &microphone_config, &microphone_device); result = ma_device_init(NULL, &microphone_config, &microphone_device);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS)
{
Log("Failed to initialize capture device.\n"); Log("Failed to initialize capture device.\n");
exit(-1); exit(-1);
} }
@ -244,11 +298,14 @@ init(void)
exit(-1); exit(-1);
} }
if (ma_mutex_init(&send_packets_mutex) != MA_SUCCESS) Log("Failed to init send mutex\n"); if (ma_mutex_init(&send_packets_mutex) != MA_SUCCESS)
if (ma_mutex_init(&play_packets_mutex) != MA_SUCCESS) Log("Failed to init play mutex\n"); Log("Failed to init send mutex\n");
if (ma_mutex_init(&play_packets_mutex) != MA_SUCCESS)
Log("Failed to init play mutex\n");
result = ma_device_start(&microphone_device); result = ma_device_start(&microphone_device);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS)
{
ma_device_uninit(&microphone_device); ma_device_uninit(&microphone_device);
Log("Failed to start device.\n"); Log("Failed to start device.\n");
exit(-1); exit(-1);
@ -264,7 +321,6 @@ init(void)
} }
Log("Initialized audio\n"); Log("Initialized audio\n");
} }
// @BeforeShip make all fprintf into logging to file, warning dialog grids on // @BeforeShip make all fprintf into logging to file, warning dialog grids on
@ -276,23 +332,41 @@ init(void)
sg_desc sgdesc = {.context = sapp_sgcontext()}; sg_desc sgdesc = {.context = sapp_sgcontext()};
sg_setup(&sgdesc); sg_setup(&sgdesc);
if (!sg_isvalid()) { if (!sg_isvalid())
{
fprintf(stderr, "Failed to create Sokol GFX context!\n"); fprintf(stderr, "Failed to create Sokol GFX context!\n");
exit(-1); exit(-1);
} }
sgp_desc sgpdesc = {0}; sgp_desc sgpdesc = {0};
sgp_setup(&sgpdesc); sgp_setup(&sgpdesc);
if (!sgp_is_valid()) { if (!sgp_is_valid())
{
fprintf(stderr, fprintf(stderr,
"Failed to create Sokol GP context: %s\n", "Failed to create Sokol GP context: %s\n",
sgp_get_error_message(sgp_get_last_error())); sgp_get_error_message(sgp_get_last_error()));
exit(-1); exit(-1);
} }
// image loading // shaders
{
// initialize shader
sgp_pipeline_desc pip_desc = {
.shader = *hueshift_program_shader_desc(sg_query_backend()),
.blend_mode = SGP_BLENDMODE_BLEND,
};
pip = sgp_make_pipeline(&pip_desc);
if (sg_query_pipeline_state(pip) != SG_RESOURCESTATE_VALID)
{
fprintf(stderr, "failed to make custom pipeline\n");
exit(-1);
}
}
// images loading
{
for (int i = 0; i < ARRLEN(boxes); i++)
{ {
for (int i = 0; i < boxes_len; i++) {
boxes[i].image = load_image(boxes[i].image_path); boxes[i].image = load_image(boxes[i].image_path);
} }
image_thrusterburn = load_image("loaded/thrusterburn.png"); image_thrusterburn = load_image("loaded/thrusterburn.png");
@ -308,11 +382,14 @@ init(void)
image_explosion = load_image("loaded/explosion.png"); image_explosion = load_image("loaded/explosion.png");
image_low_health = load_image("loaded/low_health.png"); image_low_health = load_image("loaded/low_health.png");
image_mic_muted = load_image("loaded/mic_muted.png"); image_mic_muted = load_image("loaded/mic_muted.png");
image_flag_available = load_image("loaded/flag_available.png");
image_flag_taken = load_image("loaded/flag_ripped.png");
} }
// socket initialization // socket initialization
{ {
if (enet_initialize() != 0) { if (enet_initialize() != 0)
{
fprintf(stderr, "An error occurred while initializing ENet.\n"); fprintf(stderr, "An error occurred while initializing ENet.\n");
exit(-1); exit(-1);
} }
@ -321,7 +398,8 @@ init(void)
2 /* allow up 2 channels to be used, 0 and 1 */, 2 /* allow up 2 channels to be used, 0 and 1 */,
0 /* assume any amount of incoming bandwidth */, 0 /* assume any amount of incoming bandwidth */,
0 /* assume any amount of outgoing bandwidth */); 0 /* assume any amount of outgoing bandwidth */);
if (client == NULL) { if (client == NULL)
{
fprintf( fprintf(
stderr, stderr,
"An error occurred while trying to create an ENet client host.\n"); "An error occurred while trying to create an ENet client host.\n");
@ -333,16 +411,19 @@ init(void)
enet_address_set_host(&address, SERVER_ADDRESS); enet_address_set_host(&address, SERVER_ADDRESS);
address.port = SERVER_PORT; address.port = SERVER_PORT;
peer = enet_host_connect(client, &address, 2, 0); peer = enet_host_connect(client, &address, 2, 0);
if (peer == NULL) { if (peer == NULL)
{
fprintf(stderr, fprintf(stderr,
"No available peers for initiating an ENet connection.\n"); "No available peers for initiating an ENet connection.\n");
exit(-1); exit(-1);
} }
// the timeout is the third parameter here // the timeout is the third parameter here
if (enet_host_service(client, &event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { if (enet_host_service(client, &event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT)
{
Log("Connected\n"); Log("Connected\n");
} }
else { else
{
/* Either the 5 seconds are up or a disconnect event was */ /* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */ /* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */ /* had run out without any significant event. */
@ -384,7 +465,8 @@ draw_circle(V2 point, float radius)
{ {
#define POINTS 64 #define POINTS 64
sgp_line lines[POINTS]; sgp_line lines[POINTS];
for (int i = 0; i < POINTS; i++) { for (int i = 0; i < POINTS; i++)
{
float progress = (float)i / (float)POINTS; float progress = (float)i / (float)POINTS;
float next_progress = (float)(i + 1) / (float)POINTS; float next_progress = (float)(i + 1) / (float)POINTS;
lines[i].a = (V2){.x = cosf(progress * 2.0f * PI) * radius, lines[i].a = (V2){.x = cosf(progress * 2.0f * PI) * radius,
@ -429,18 +511,140 @@ ui(bool draw, float dt, float width, float height)
{ {
static float cur_opacity = 1.0f; static float cur_opacity = 1.0f;
cur_opacity = lerp(cur_opacity, myentity() != NULL ? 1.0f : 0.0f, dt * 5.0f); cur_opacity = lerp(cur_opacity, myentity() != NULL ? 1.0f : 0.0f, dt * 5.0f);
if (cur_opacity <= 0.01f) { if (cur_opacity <= 0.01f)
{
return; return;
} }
if (draw) if (draw)
sgp_push_transform(); sgp_push_transform();
// draw flags
static V2 flag_pos[SquadLast] = {0};
static float flag_rot[SquadLast] = {0};
static float flag_scaling_increase[SquadLast] = {0};
static bool choosing_flags = false;
const float flag_padding = 70.0f;
const float center_panel_height = 200.0f;
static float center_panel_width = 0.0f;
const float target_center_panel_width = ((SquadLast) + 2) * flag_padding;
#define FLAG_ITER(i) for (int i = 0; i < SquadLast; i++)
{
FLAG_ITER(i)
{
V2 target_pos = {0};
float target_rot = 0.0f;
float flag_progress = (float)i / (float)(SquadLast - 1.0f);
if (choosing_flags)
{
target_pos.x = width / 2.0f + lerp(-center_panel_width / 2.0f + flag_padding, center_panel_width / 2.0f - flag_padding, flag_progress);
target_pos.y = height * 0.5f;
target_rot = 0.0f;
}
else
{
target_pos.x = 25.0f;
target_pos.y = 200.0f;
target_rot = lerp(-PI / 3.0f, PI / 3.0f, flag_progress) + PI / 2.0f;
}
flag_pos[i] = V2lerp(flag_pos[i], target_pos, dt * 5.0f);
flag_rot[i] = lerp_angle(flag_rot[i], target_rot, dt * 5.0f);
}
center_panel_width = lerp(center_panel_width, choosing_flags ? target_center_panel_width : 0.0f, 6.0f * dt);
// center panel
{
AABB panel_rect = (AABB){
.x = width / 2.0f - center_panel_width / 2.0f,
.y = height / 2.0f - center_panel_height / 2.0f,
.width = center_panel_width,
.height = center_panel_height,
};
if (choosing_flags && mouse_pressed && !has_point(panel_rect, mouse_pos))
{
mouse_pressed = false;
choosing_flags = false;
}
if (draw)
{
sgp_set_color(0.7f, 0.7f, 0.7f, 0.5f);
sgp_draw_filled_rect(panel_rect.x, panel_rect.y, panel_rect.width, panel_rect.height);
}
}
FLAG_ITER(i)
{
enum Squad this_squad = (enum Squad)i;
bool this_squad_available = true;
if (this_squad != SquadNone)
PLAYERS_ITER(gs.players, other_player)
{
if (other_player->squad == this_squad)
{
this_squad_available = false;
break;
}
}
float size = 128.0f;
bool hovering = V2dist(mouse_pos, flag_pos[i]) < size * 0.25f && this_squad_available;
if (!choosing_flags && hovering && mouse_pressed)
{
choosing_flags = true;
mouse_pressed = false;
}
if (this_squad_available && choosing_flags && hovering && mouse_pressed)
{
take_over_squad = this_squad;
mouse_pressed = false;
}
flag_scaling_increase[i] = lerp(flag_scaling_increase[i], hovering ? 0.2f : 0.0f, dt * 9.0f);
size *= 1.0f + flag_scaling_increase[i];
if (draw)
{
transform_scope
{
if (this_squad_available)
{
sgp_set_image(0, image_flag_available);
}
else
{
sgp_set_image(0, image_flag_taken);
}
sgp_set_pipeline(pip);
struct SquadMeta meta = squad_meta(this_squad);
hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless;
uniform.target_hue = meta.hue;
sgp_set_uniform(&uniform, sizeof(hueshift_uniforms_t));
sgp_rotate_at(flag_rot[i], flag_pos[i].x, flag_pos[i].y);
sgp_scale_at(1.0f, -1.0f, flag_pos[i].x, flag_pos[i].y); // images upside down by default :(
draw_texture_centered(flag_pos[i], size);
sgp_reset_image(0);
sgp_reset_pipeline();
}
}
}
}
#undef FLAG_ITER
// draw spice bar // draw spice bar
if (draw) { if (draw)
{
static float damage = 0.5f; static float damage = 0.5f;
if (myentity() != NULL) { if (myentity() != NULL)
{
damage = myentity()->damage; damage = myentity()->damage;
} }
@ -456,7 +660,8 @@ ui(bool draw, float dt, float width, float height)
// draw muted // draw muted
static float muted_opacity = 0.0f; static float muted_opacity = 0.0f;
if (draw) { if (draw)
{
muted_opacity = lerp(muted_opacity, muted ? 1.0f : 0.0f, 8.0f * dt); muted_opacity = lerp(muted_opacity, muted ? 1.0f : 0.0f, 8.0f * dt);
sgp_set_color(1.0f, 1.0f, 1.0f, muted_opacity); sgp_set_color(1.0f, 1.0f, 1.0f, muted_opacity);
float size_x = 150.0f; float size_x = 150.0f;
@ -465,7 +670,8 @@ ui(bool draw, float dt, float width, float height)
float x = width - size_x - 40.0f; float x = width - size_x - 40.0f;
float y = height - size_y - 40.0f; float y = height - size_y - 40.0f;
transform_scope{ transform_scope
{
sgp_scale_at(1.0f, -1.0f, x + size_x / 2.0f, y + size_y / 2.0f); sgp_scale_at(1.0f, -1.0f, x + size_x / 2.0f, y + size_y / 2.0f);
sgp_draw_textured_rect(x, y, size_x, size_y); sgp_draw_textured_rect(x, y, size_x, size_y);
sgp_reset_image(0); sgp_reset_image(0);
@ -476,7 +682,7 @@ ui(bool draw, float dt, float width, float height)
{ {
float itemframe_width = (float)sg_query_image_info(image_itemframe).width * 2.0f; float itemframe_width = (float)sg_query_image_info(image_itemframe).width * 2.0f;
float itemframe_height = (float)sg_query_image_info(image_itemframe).height * 2.0f; float itemframe_height = (float)sg_query_image_info(image_itemframe).height * 2.0f;
float total_width = itemframe_width * boxes_len; float total_width = itemframe_width * ARRLEN(boxes);
float item_width = itemframe_width * 0.75f; float item_width = itemframe_width * 0.75f;
float item_height = itemframe_height * 0.75f; float item_height = itemframe_height * 0.75f;
float item_offset_x = (itemframe_width - item_width) / 2.0f; float item_offset_x = (itemframe_width - item_width) / 2.0f;
@ -484,7 +690,8 @@ ui(bool draw, float dt, float width, float height)
float x = width / 2.0f - total_width / 2.0f; float x = width / 2.0f - total_width / 2.0f;
float y = height - itemframe_height * 1.5f; float y = height - itemframe_height * 1.5f;
for (int i = 0; i < boxes_len; i++) { for (int i = 0; i < ARRLEN(boxes); i++)
{
if (has_point( if (has_point(
(AABB){ (AABB){
.x = x, .x = x,
@ -492,19 +699,23 @@ ui(bool draw, float dt, float width, float height)
.width = itemframe_width, .width = itemframe_width,
.height = itemframe_height, .height = itemframe_height,
}, },
mouse_pos) mouse_pos) &&
&& mouse_pressed) { mouse_pressed)
{
// "handle" mouse pressed // "handle" mouse pressed
attempt_to_build(i); attempt_to_build(i);
mouse_pressed = false; mouse_pressed = false;
} }
if (draw) { if (draw)
{
sgp_set_color(1.0f, 1.0f, 1.0f, cur_opacity); sgp_set_color(1.0f, 1.0f, 1.0f, cur_opacity);
if (cur_editing_boxtype == i) { if (cur_editing_boxtype == i)
{
sgp_set_image(0, image_itemframe_selected); sgp_set_image(0, image_itemframe_selected);
} }
else { else
{
sgp_set_image(0, image_itemframe); sgp_set_image(0, image_itemframe);
} }
sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height); sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height);
@ -513,7 +724,8 @@ ui(bool draw, float dt, float width, float height)
{ {
sgp_set_image(0, info.image); sgp_set_image(0, info.image);
} }
else { else
{
sgp_set_image(0, image_mystery); sgp_set_image(0, image_mystery);
} }
transform_scope transform_scope
@ -538,8 +750,10 @@ static void draw_dots(V2 camera_pos, float gap)
{ {
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
const int num = 100; const int num = 100;
for (int x = -num; x < num; x++) { for (int x = -num; x < num; x++)
for (int y = -num; y < num; y++) { {
for (int y = -num; y < num; y++)
{
V2 star = (V2){(float)x * gap, (float)y * gap}; V2 star = (V2){(float)x * gap, (float)y * gap};
if (V2lengthsqr(V2sub(star, camera_pos)) > VISION_RADIUS * VISION_RADIUS) if (V2lengthsqr(V2sub(star, camera_pos)) > VISION_RADIUS * VISION_RADIUS)
continue; continue;
@ -561,12 +775,15 @@ frame(void)
// pressed input management // pressed input management
{ {
for (int i = 0; i < SAPP_KEYCODE_MENU; i++) { for (int i = 0; i < SAPP_KEYCODE_MENU; i++)
if (keypressed[i].frame < sapp_frame_count()) { {
if (keypressed[i].frame < sapp_frame_count())
{
keypressed[i].pressed = false; keypressed[i].pressed = false;
} }
} }
if (mouse_pressed_frame < sapp_frame_count()) { if (mouse_pressed_frame < sapp_frame_count())
{
mouse_pressed = false; mouse_pressed = false;
} }
} }
@ -574,16 +791,21 @@ frame(void)
// networking // networking
{ {
ENetEvent event; ENetEvent event;
while (true) { while (true)
{
int enet_status = enet_host_service(client, &event, 0); int enet_status = enet_host_service(client, &event, 0);
if (enet_status > 0) { if (enet_status > 0)
switch (event.type) { {
case ENET_EVENT_TYPE_CONNECT: { switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
{
Log("New client from host %x\n", event.peer->address.host); Log("New client from host %x\n", event.peer->address.host);
break; break;
} }
case ENET_EVENT_TYPE_RECEIVE: { case ENET_EVENT_TYPE_RECEIVE:
{
char *decompressed = malloc(sizeof *decompressed * MAX_SERVER_TO_CLIENT); // @Robust no malloc char *decompressed = malloc(sizeof *decompressed * MAX_SERVER_TO_CLIENT); // @Robust no malloc
size_t decompressed_max_len = MAX_SERVER_TO_CLIENT; size_t decompressed_max_len = MAX_SERVER_TO_CLIENT;
assert(LZO1X_MEM_DECOMPRESS == 0); assert(LZO1X_MEM_DECOMPRESS == 0);
@ -599,7 +821,8 @@ frame(void)
server_to_client_deserialize(&msg, decompressed, decompressed_max_len, false); server_to_client_deserialize(&msg, decompressed, decompressed_max_len, false);
myplayer = msg.your_player; myplayer = msg.your_player;
} }
else { else
{
Log("Couldn't decompress gamestate packet, error code %d from lzo\n", return_value); Log("Couldn't decompress gamestate packet, error code %d from lzo\n", return_value);
} }
ma_mutex_unlock(&play_packets_mutex); ma_mutex_unlock(&play_packets_mutex);
@ -608,17 +831,20 @@ frame(void)
break; break;
} }
case ENET_EVENT_TYPE_DISCONNECT: { case ENET_EVENT_TYPE_DISCONNECT:
{
fprintf(stderr, "Disconnected from server\n"); fprintf(stderr, "Disconnected from server\n");
exit(-1); exit(-1);
break; break;
} }
} }
} }
else if (enet_status == 0) { else if (enet_status == 0)
{
break; break;
} }
else if (enet_status < 0) { else if (enet_status < 0)
{
fprintf(stderr, "Error receiving enet events: %d\n", enet_status); fprintf(stderr, "Error receiving enet events: %d\n", enet_status);
break; break;
} }
@ -630,10 +856,10 @@ frame(void)
V2 build_target_pos = {0}; V2 build_target_pos = {0};
float build_target_rotation = 0.0f; float build_target_rotation = 0.0f;
static V2 camera_pos = { static V2 camera_pos = {
0 0}; // keeps camera at same position after player death
}; // keeps camera at same position after player death
V2 world_mouse_pos = mouse_pos; // processed later in scope V2 world_mouse_pos = mouse_pos; // processed later in scope
struct BuildPreviewInfo { struct BuildPreviewInfo
{
V2 grid_pos; V2 grid_pos;
float grid_rotation; float grid_rotation;
} build_preview = {0}; } build_preview = {0};
@ -645,7 +871,8 @@ frame(void)
// calculate world position and camera // calculate world position and camera
{ {
if (myentity() != NULL) { if (myentity() != NULL)
{
camera_pos = entity_pos(myentity()); camera_pos = entity_pos(myentity());
} }
world_mouse_pos = V2sub(world_mouse_pos, (V2){.x = width / 2.0f, .y = height / 2.0f}); world_mouse_pos = V2sub(world_mouse_pos, (V2){.x = width / 2.0f, .y = height / 2.0f});
@ -657,14 +884,17 @@ frame(void)
// calculate build preview stuff // calculate build preview stuff
EntityID grid_to_build_on = (EntityID){0}; EntityID grid_to_build_on = (EntityID){0};
V2 possibly_local_hand_pos = (V2){0}; V2 possibly_local_hand_pos = (V2){0};
if (myentity() != NULL) { if (myentity() != NULL)
{
hand_pos = V2sub(world_mouse_pos, entity_pos(myentity())); hand_pos = V2sub(world_mouse_pos, entity_pos(myentity()));
float hand_len = V2length(hand_pos); float hand_len = V2length(hand_pos);
if (hand_len > MAX_HAND_REACH) { if (hand_len > MAX_HAND_REACH)
{
hand_at_arms_length = true; hand_at_arms_length = true;
hand_len = MAX_HAND_REACH; hand_len = MAX_HAND_REACH;
} }
else { else
{
hand_at_arms_length = false; hand_at_arms_length = false;
} }
hand_pos = V2scale(V2normalize(hand_pos), hand_len); hand_pos = V2scale(V2normalize(hand_pos), hand_len);
@ -672,17 +902,20 @@ frame(void)
possibly_local_hand_pos = V2sub(hand_pos, entity_pos(myentity())); possibly_local_hand_pos = V2sub(hand_pos, entity_pos(myentity()));
Entity *placing_grid = closest_to_point_in_radius(&gs, hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP); Entity *placing_grid = closest_to_point_in_radius(&gs, hand_pos, BUILD_BOX_SNAP_DIST_TO_SHIP);
if (placing_grid == NULL) { if (placing_grid == NULL)
{
build_preview = (struct BuildPreviewInfo){ build_preview = (struct BuildPreviewInfo){
.grid_pos = hand_pos, .grid_pos = hand_pos,
.grid_rotation = 0.0f, .grid_rotation = 0.0f,
}; };
} }
else { else
{
grid_to_build_on = get_id(&gs, placing_grid); grid_to_build_on = get_id(&gs, placing_grid);
hand_pos = grid_snapped_box_pos(placing_grid, hand_pos); hand_pos = grid_snapped_box_pos(placing_grid, hand_pos);
possibly_local_hand_pos = grid_world_to_local(placing_grid, hand_pos); possibly_local_hand_pos = grid_world_to_local(placing_grid, hand_pos);
build_preview = (struct BuildPreviewInfo){ .grid_pos = entity_pos(placing_grid), build_preview = (struct BuildPreviewInfo){
.grid_pos = entity_pos(placing_grid),
.grid_rotation = entity_rotation(placing_grid), .grid_rotation = entity_rotation(placing_grid),
}; };
} }
@ -704,8 +937,10 @@ frame(void)
cur_input_frame.seat_action = keypressed[SAPP_KEYCODE_G].pressed; cur_input_frame.seat_action = keypressed[SAPP_KEYCODE_G].pressed;
cur_input_frame.grid_hand_pos_local_to = grid_to_build_on; cur_input_frame.grid_hand_pos_local_to = grid_to_build_on;
cur_input_frame.hand_pos = possibly_local_hand_pos; cur_input_frame.hand_pos = possibly_local_hand_pos;
cur_input_frame.take_over_squad = take_over_squad;
if (mouse_pressed && cur_editing_boxtype != -1) { if (mouse_pressed && cur_editing_boxtype != -1)
{
cur_input_frame.dobuild = mouse_pressed; cur_input_frame.dobuild = mouse_pressed;
cur_input_frame.build_type = cur_editing_boxtype; cur_input_frame.build_type = cur_editing_boxtype;
cur_input_frame.build_rotation = cur_editing_rotation; cur_input_frame.build_rotation = cur_editing_rotation;
@ -726,9 +961,13 @@ frame(void)
input_differs = input_differs || cur_input_frame.build_rotation != latest.build_rotation; input_differs = input_differs || cur_input_frame.build_rotation != latest.build_rotation;
input_differs = input_differs || !entityids_same(cur_input_frame.grid_hand_pos_local_to, latest.grid_hand_pos_local_to); input_differs = input_differs || !entityids_same(cur_input_frame.grid_hand_pos_local_to, latest.grid_hand_pos_local_to);
if (input_differs) { input_differs = input_differs || cur_input_frame.take_over_squad != latest.take_over_squad;
if (input_differs)
{
InputFrame last_frame = client_to_server.inputs[0]; InputFrame last_frame = client_to_server.inputs[0];
for (int i = 0; i < INPUT_BUFFER - 1; i++) { for (int i = 0; i < INPUT_BUFFER - 1; i++)
{
InputFrame last_last_frame = last_frame; InputFrame last_last_frame = last_frame;
last_frame = client_to_server.inputs[i + 1]; last_frame = client_to_server.inputs[i + 1];
client_to_server.inputs[i + 1] = last_last_frame; client_to_server.inputs[i + 1] = last_last_frame;
@ -744,7 +983,8 @@ frame(void)
} }
static int64_t last_sent_input_time = 0; static int64_t last_sent_input_time = 0;
if (stm_sec(stm_diff(stm_now(), last_sent_input_time)) > TIME_BETWEEN_INPUT_PACKETS) { if (stm_sec(stm_diff(stm_now(), last_sent_input_time)) > TIME_BETWEEN_INPUT_PACKETS)
{
ma_mutex_lock(&send_packets_mutex); ma_mutex_lock(&send_packets_mutex);
client_to_server.mic_data = &packets_to_send; client_to_server.mic_data = &packets_to_send;
char serialized[MAX_CLIENT_TO_SERVER] = {0}; char serialized[MAX_CLIENT_TO_SERVER] = {0};
@ -757,12 +997,12 @@ frame(void)
enet_peer_send(peer, 0, packet); // @Robust error check this enet_peer_send(peer, 0, packet); // @Robust error check this
last_sent_input_time = stm_now(); last_sent_input_time = stm_now();
} }
else { else
{
Log("Failed to serialize client to server!\n"); Log("Failed to serialize client to server!\n");
} }
client_to_server.mic_data = NULL; client_to_server.mic_data = NULL;
ma_mutex_unlock(&send_packets_mutex); ma_mutex_unlock(&send_packets_mutex);
} }
} }
@ -845,7 +1085,8 @@ frame(void)
draw_dots(camera_pos, 1.5f); // in plane dots draw_dots(camera_pos, 1.5f); // in plane dots
// hand reached limit circle // hand reached limit circle
if (myentity() != NULL) { if (myentity() != NULL)
{
static float hand_reach_alpha = 1.0f; static float hand_reach_alpha = 1.0f;
hand_reach_alpha = lerp(hand_reach_alpha, hand_at_arms_length ? 1.0f : 0.0f, dt * 5.0f); hand_reach_alpha = lerp(hand_reach_alpha, hand_at_arms_length ? 1.0f : 0.0f, dt * 5.0f);
sgp_set_color(1.0f, 1.0f, 1.0f, hand_reach_alpha); sgp_set_color(1.0f, 1.0f, 1.0f, hand_reach_alpha);
@ -862,13 +1103,15 @@ frame(void)
float halfbox = BOX_SIZE / 2.0f; float halfbox = BOX_SIZE / 2.0f;
// mouse frozen, debugging tool // mouse frozen, debugging tool
if (mouse_frozen) { if (mouse_frozen)
{
sgp_set_color(1.0f, 0.0f, 0.0f, 0.5f); sgp_set_color(1.0f, 0.0f, 0.0f, 0.5f);
sgp_draw_filled_rect(world_mouse_pos.x, world_mouse_pos.y, 0.1f, 0.1f); sgp_draw_filled_rect(world_mouse_pos.x, world_mouse_pos.y, 0.1f, 0.1f);
} }
// building preview // building preview
if (cur_editing_boxtype != -1) { if (cur_editing_boxtype != -1)
{
sgp_set_color(0.5f, 0.5f, 0.5f, (sinf((float)time * 9.0f) + 1.0f) / 3.0f + 0.2f); sgp_set_color(0.5f, 0.5f, 0.5f, (sinf((float)time * 9.0f) + 1.0f) / 3.0f + 0.2f);
transform_scope transform_scope
@ -886,7 +1129,8 @@ frame(void)
static float player_scaling = 1.0f; static float player_scaling = 1.0f;
player_scaling = lerp(player_scaling, zoom < 6.5f ? 100.0f : 1.0f, dt * 7.0f); player_scaling = lerp(player_scaling, zoom < 6.5f ? 100.0f : 1.0f, dt * 7.0f);
for (size_t i = 0; i < gs.cur_next_entity; i++) { for (size_t i = 0; i < gs.cur_next_entity; i++)
{
Entity *e = &gs.entities[i]; Entity *e = &gs.entities[i];
if (!e->exists) if (!e->exists)
continue; continue;
@ -912,7 +1156,8 @@ frame(void)
} }
} }
#endif #endif
if (b->box_type == BoxBattery) { if (b->box_type == BoxBattery)
{
float cur_alpha = sgp_get_color().a; float cur_alpha = sgp_get_color().a;
Color from = WHITE; Color from = WHITE;
Color to = colhex(255, 0, 0); Color to = colhex(255, 0, 0);
@ -925,7 +1170,8 @@ frame(void)
entity_pos(b).x, entity_pos(b).x,
entity_pos(b).y); entity_pos(b).y);
if (b->box_type == BoxThruster) { if (b->box_type == BoxThruster)
{
transform_scope transform_scope
{ {
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
@ -981,14 +1227,25 @@ frame(void)
sgp_draw_line(grid_com(g).x, grid_com(g).y, to.x, to.y); sgp_draw_line(grid_com(g).x, grid_com(g).y, to.x, to.y);
#endif #endif
} }
if (e->is_player && get_entity(&gs, e->currently_inside_of_box) == NULL) {
// draw player
if (e->is_player && get_entity(&gs, e->currently_inside_of_box) == NULL)
{
transform_scope transform_scope
{ {
sgp_rotate_at(entity_rotation(e), entity_pos(e).x, entity_pos(e).y); sgp_rotate_at(entity_rotation(e), entity_pos(e).x, entity_pos(e).y);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f);
sgp_set_pipeline(pip);
struct SquadMeta meta = squad_meta(e->presenting_squad);
hueshift_uniforms_t uniform = {0};
uniform.is_colorless = meta.is_colorless;
uniform.target_hue = meta.hue;
sgp_set_uniform(&uniform, sizeof(hueshift_uniforms_t));
sgp_set_image(0, image_player); sgp_set_image(0, image_player);
draw_texture_rectangle_centered(entity_pos(e), V2scale(PLAYER_SIZE, player_scaling)); draw_texture_rectangle_centered(entity_pos(e), V2scale(PLAYER_SIZE, player_scaling));
sgp_reset_image(0); sgp_reset_image(0);
sgp_reset_pipeline();
} }
} }
if (e->is_explosion) if (e->is_explosion)
@ -1045,6 +1302,8 @@ frame(void)
void cleanup(void) void cleanup(void)
{ {
sg_destroy_pipeline(pip);
ma_mutex_lock(&server_info.info_mutex); ma_mutex_lock(&server_info.info_mutex);
server_info.should_quit = true; server_info.should_quit = true;
ma_mutex_unlock(&server_info.info_mutex); ma_mutex_unlock(&server_info.info_mutex);
@ -1070,14 +1329,17 @@ void cleanup(void)
void event(const sapp_event *e) void event(const sapp_event *e)
{ {
switch (e->type) { switch (e->type)
{
case SAPP_EVENTTYPE_KEY_DOWN: case SAPP_EVENTTYPE_KEY_DOWN:
#ifdef DEBUG_TOOLS #ifdef DEBUG_TOOLS
if (e->key_code == SAPP_KEYCODE_T) { if (e->key_code == SAPP_KEYCODE_T)
{
mouse_frozen = !mouse_frozen; mouse_frozen = !mouse_frozen;
} }
#endif #endif
if (e->key_code == SAPP_KEYCODE_R) { if (e->key_code == SAPP_KEYCODE_R)
{
cur_editing_rotation += 1; cur_editing_rotation += 1;
cur_editing_rotation %= RotationLast; cur_editing_rotation %= RotationLast;
} }
@ -1097,20 +1359,24 @@ void event(const sapp_event* e)
} }
int key_num = e->key_code - SAPP_KEYCODE_0; int key_num = e->key_code - SAPP_KEYCODE_0;
int target_box = key_num - 1; int target_box = key_num - 1;
if (target_box < BoxLast && target_box >= 0) { if (target_box < BoxLast && target_box >= 0)
{
attempt_to_build(target_box); attempt_to_build(target_box);
} }
if (!mouse_frozen) { if (!mouse_frozen)
{
keydown[e->key_code] = true; keydown[e->key_code] = true;
if (keypressed[e->key_code].frame == 0) { if (keypressed[e->key_code].frame == 0)
{
keypressed[e->key_code].pressed = true; keypressed[e->key_code].pressed = true;
keypressed[e->key_code].frame = e->frame_count; keypressed[e->key_code].frame = e->frame_count;
} }
} }
break; break;
case SAPP_EVENTTYPE_KEY_UP: case SAPP_EVENTTYPE_KEY_UP:
if (!mouse_frozen) { if (!mouse_frozen)
{
keydown[e->key_code] = false; keydown[e->key_code] = false;
keypressed[e->key_code].pressed = false; keypressed[e->key_code].pressed = false;
@ -1122,28 +1388,34 @@ void event(const sapp_event* e)
zoom_target = clamp(zoom_target, 0.5f, 900.0f); zoom_target = clamp(zoom_target, 0.5f, 900.0f);
break; break;
case SAPP_EVENTTYPE_MOUSE_DOWN: case SAPP_EVENTTYPE_MOUSE_DOWN:
if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT) { if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT)
{
mouse_pressed = true; mouse_pressed = true;
mouse_pressed_frame = e->frame_count; mouse_pressed_frame = e->frame_count;
} }
if (e->mouse_button == SAPP_MOUSEBUTTON_RIGHT) { if (e->mouse_button == SAPP_MOUSEBUTTON_RIGHT)
{
right_mouse_down = true; right_mouse_down = true;
} }
break; break;
case SAPP_EVENTTYPE_MOUSE_UP: case SAPP_EVENTTYPE_MOUSE_UP:
if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT) { if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT)
{
mouse_pressed = false; mouse_pressed = false;
mouse_pressed_frame = 0; mouse_pressed_frame = 0;
} }
if (e->mouse_button == SAPP_MOUSEBUTTON_RIGHT) { if (e->mouse_button == SAPP_MOUSEBUTTON_RIGHT)
{
right_mouse_down = false; right_mouse_down = false;
} }
break; break;
case SAPP_EVENTTYPE_MOUSE_MOVE: case SAPP_EVENTTYPE_MOUSE_MOVE:
if (!mouse_frozen) { if (!mouse_frozen)
{
mouse_pos = (V2){.x = e->mouse_x, .y = e->mouse_y}; mouse_pos = (V2){.x = e->mouse_x, .y = e->mouse_y};
} }
if (right_mouse_down) { if (right_mouse_down)
{
funval += e->mouse_dx; funval += e->mouse_dx;
Log("Funval %f\n", funval); Log("Funval %f\n", funval);
} }
@ -1158,7 +1430,8 @@ sokol_main(int argc, char* argv[])
stm_setup(); stm_setup();
ma_mutex_init(&server_info.info_mutex); ma_mutex_init(&server_info.info_mutex);
server_info.world_save = "debug_world.bin"; server_info.world_save = "debug_world.bin";
if (argc > 1) { if (argc > 1)
{
server_thread_handle = (void *)_beginthread(server, 0, (void *)&server_info); server_thread_handle = (void *)_beginthread(server, 0, (void *)&server_info);
hosting = true; hosting = true;
} }

@ -253,6 +253,7 @@ void server(void* info_raw)
#ifdef UNLOCK_ALL #ifdef UNLOCK_ALL
gs.players[player_slot].unlocked_bombs = true; gs.players[player_slot].unlocked_bombs = true;
#endif #endif
gs.players[player_slot].squad = SquadPurple;
} }
} }
break; break;
@ -296,6 +297,8 @@ void server(void* info_raw)
// for these "event" inputs, only modify the current input if the event is true. // for these "event" inputs, only modify the current input if the event is true.
// while processing the gamestate, will mark it as false once processed. This // while processing the gamestate, will mark it as false once processed. This
// prevents setting the event input to false before it's been processed. // prevents setting the event input to false before it's been processed.
if (cur_input.take_over_squad >= 0)
gs.players[player_slot].input.take_over_squad = cur_input.take_over_squad;
if (cur_input.seat_action) if (cur_input.seat_action)
{ {
gs.players[player_slot].input.seat_action = cur_input.seat_action; gs.players[player_slot].input.seat_action = cur_input.seat_action;

@ -0,0 +1,6 @@
WHERE sokol-shdc.exe
IF %ERRORLEVEL% NEQ 0 ECHO ERROR download sokol-shdc from https://github.com/floooh/sokol-tools-bin/blob/master/bin/win32/sokol-shdc.exe and put it in this folder
@REM example of how to compile shaders: sokol-shdc.exe --input triangle.glsl --output triangle.gen.h --slang glsl330:hlsl5:metal_macos
sokol-shdc.exe --format sokol --input hueshift.glsl --output hueshift.gen.h --slang glsl330:hlsl5:metal_macos

@ -121,6 +121,16 @@ enum CompassRotation
RotationLast, RotationLast,
}; };
enum Squad
{
SquadNone,
SquadRed,
SquadGreen,
SquadBlue,
SquadPurple,
SquadLast,
};
// when generation is 0, invalid ID // when generation is 0, invalid ID
typedef struct EntityID typedef struct EntityID
{ {
@ -141,6 +151,8 @@ typedef struct InputFrame
size_t id; // each input has unique, incrementing, I.D, so server doesn't double process inputs. Inputs to server should be ordered from 0-max like biggest id-smallest. This is done so if packet loss server still processes input size_t id; // each input has unique, incrementing, I.D, so server doesn't double process inputs. Inputs to server should be ordered from 0-max like biggest id-smallest. This is done so if packet loss server still processes input
V2 movement; V2 movement;
int take_over_squad; // -1 means not taking over any squad
bool seat_action; bool seat_action;
EntityID seat_to_inhabit; EntityID seat_to_inhabit;
V2 hand_pos; // local to player transationally but not rotationally unless field below is not null, then it's local to that grid V2 hand_pos; // local to player transationally but not rotationally unless field below is not null, then it's local to that grid
@ -172,6 +184,7 @@ typedef struct Entity
// player // player
bool is_player; bool is_player;
enum Squad presenting_squad;
EntityID currently_inside_of_box; EntityID currently_inside_of_box;
float goldness; // how much the player is a winner float goldness; // how much the player is a winner
@ -206,6 +219,7 @@ typedef struct Player
{ {
bool connected; bool connected;
bool unlocked_bombs; bool unlocked_bombs;
enum Squad squad;
EntityID entity; EntityID entity;
EntityID last_used_medbay; EntityID last_used_medbay;
InputFrame input; InputFrame input;
@ -236,6 +250,7 @@ typedef struct GameState
#define PLAYERS_ITER(players, cur) for(Player * cur = players; cur < players+MAX_PLAYERS; cur++) if(cur->connected) #define PLAYERS_ITER(players, cur) for(Player * cur = players; cur < players+MAX_PLAYERS; cur++) if(cur->connected)
#define PI 3.14159f #define PI 3.14159f
#define TAU (PI*2.0f)
// returns in radians // returns in radians
static float rotangle(enum CompassRotation rot) static float rotangle(enum CompassRotation rot)
@ -391,8 +406,6 @@ static OpusPacket* push_packet(OpusBuffer* buff)
return to_return; return to_return;
} }
// how many unpopped packets there are, can't check for null on pop_packet because
// could be a skipped packet. This is used in a for loop to flush a packet buffer
static int num_queued_packets(OpusBuffer* buff) static int num_queued_packets(OpusBuffer* buff)
{ {
int to_return = 0; int to_return = 0;
@ -558,6 +571,12 @@ static float lerp(float a, float b, float f)
return a * (1.0f - f) + (b * f); return a * (1.0f - f) + (b * f);
} }
static float lerp_angle(float p_from, float p_to, float p_weight) {
float difference = fmodf(p_to - p_from, (float)TAU);
float distance = fmodf(2.0f * difference, (float)TAU) - difference;
return p_from + distance * p_weight;
}
static V2 V2floor(V2 p) static V2 V2floor(V2 p)
{ {
return (V2) { floorf(p.x), floorf(p.y) }; return (V2) { floorf(p.x), floorf(p.y) };

Loading…
Cancel
Save