@ -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 ;
}
}