@ -33,39 +33,46 @@
# include "hueshift.gen.h"
# include "hueshift.gen.h"
static sg_pipeline pip ;
static sg_pipeline pip ;
static struct GameState gs = { 0 } ;
static struct GameState gs = { 0 } ;
static int my player = - 1 ;
static int my _ player_index = - 1 ;
static bool right_mouse_down = false ;
static bool right_mouse_down = false ;
# define MAX_KEYDOWN SAPP_KEYCODE_MENU
# define MAX_KEYDOWN SAPP_KEYCODE_MENU
static bool keydown [ MAX_KEYDOWN ] = { 0 } ;
static bool keydown [ MAX_KEYDOWN ] = { 0 } ;
typedef struct KeyPressed
typedef struct KeyPressed
{
{
bool pressed ;
bool pressed ;
uint64_t frame ;
uint64_t frame ;
} KeyPressed ;
} KeyPressed ;
static KeyPressed keypressed [ MAX_KEYDOWN ] = { 0 } ;
static KeyPressed keypressed [ MAX_KEYDOWN ] = { 0 } ;
static V2 mouse_pos = { 0 } ;
static V2 mouse_pos = { 0 } ;
static bool fullscreened = false ;
static bool fullscreened = false ;
static bool build_pressed = false ;
static bool build_pressed = false ;
static bool interact_pressed = false ;
static bool interact_pressed = false ;
# define MAX_MOUSEBUTTON SAPP_MOUSEBUTTON_MIDDLE
# define MAX_MOUSEBUTTON (SAPP_MOUSEBUTTON_MIDDLE+1)
static bool mousedown [ MAX_MOUSEBUTTON ] = { 0 } ;
typedef struct MousePressed
typedef struct MousePressed
{
{
bool pressed ;
bool pressed ;
uint64_t frame ;
uint64_t frame ;
} MousePressed ;
} MousePressed ;
static MousePressed mousepressed [ MAX_MOUSEBUTTON ] = { 0 } ;
static MousePressed mousepressed [ MAX_MOUSEBUTTON ] = { 0 } ;
static EntityID maybe_inviting_this_player = { 0 } ;
bool confirm_invite_this_player = false ;
bool accept_invite = false ;
bool reject_invite = false ;
static V2 camera_pos = { 0 } ; // it being a global variable keeps camera at same position after player death
static float player_scaling = 1.0f ;
static bool mouse_frozen = false ; // @BeforeShip make this debug only thing
static bool mouse_frozen = false ; // @BeforeShip make this debug only thing
static float funval = 0.0f ; // easy to play with value controlled by left mouse button when held
static float funval = 0.0f ; // easy to play with value controlled by left mouse button when held
// down @BeforeShip remove on release builds
// down @BeforeShip remove on release builds
static struct ClientToServer client_to_server = { 0 } ; // buffer of inputs
static struct ClientToServer client_to_server = { 0 } ; // buffer of inputs
static ENetHost * client ;
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
static enum Squad take_over_squad = ( enum Squad ) - 1 ; // -1 means not taking over any squad
// images
// images
static sg_image image_itemframe ;
static sg_image image_itemframe ;
@ -83,6 +90,9 @@ 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_available ;
static sg_image image_flag_taken ;
static sg_image image_flag_taken ;
static sg_image image_squad_invite ;
static sg_image image_check ;
static sg_image image_no ;
static int cur_editing_boxtype = - 1 ;
static int cur_editing_boxtype = - 1 ;
static int cur_editing_rotation = 0 ;
static int cur_editing_rotation = 0 ;
@ -91,21 +101,21 @@ static int cur_editing_rotation = 0;
static bool muted = false ;
static bool muted = false ;
static ma_device microphone_device ;
static ma_device microphone_device ;
static ma_device speaker_device ;
static ma_device speaker_device ;
OpusEncoder * enc ;
OpusEncoder * enc ;
OpusDecoder * dec ;
OpusDecoder * dec ;
OpusBuffer packets_to_send = { 0 } ;
OpusBuffer packets_to_send = { 0 } ;
OpusBuffer packets_to_play = { 0 } ;
OpusBuffer packets_to_play = { 0 } ;
ma_mutex send_packets_mutex = { 0 } ;
ma_mutex send_packets_mutex = { 0 } ;
ma_mutex play_packets_mutex = { 0 } ;
ma_mutex play_packets_mutex = { 0 } ;
// server thread
// server thread
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 ;
bool needs_tobe_unlocked ;
bool needs_tobe_unlocked ;
} boxes [ ] = {
} boxes [ ] = {
@ -140,6 +150,7 @@ static struct BoxInfo
. needs_tobe_unlocked = true ,
. needs_tobe_unlocked = true ,
} ,
} ,
} ;
} ;
# define ENTITIES_ITER(cur) for(Entity* cur = gs.entities; cur < gs.entities + gs.cur_next_entity; cur++) if(cur->exists)
# define ARRLEN(arr) (sizeof(arr) / sizeof(*arr))
# define ARRLEN(arr) (sizeof(arr) / sizeof(*arr))
static struct SquadMeta
static struct SquadMeta
@ -178,11 +189,11 @@ struct SquadMeta squad_meta(enum Squad squad)
return squad_metas [ i ] ;
return squad_metas [ i ] ;
}
}
Log ( " Could not find squad %d! \n " , squad ) ;
Log ( " Could not find squad %d! \n " , squad ) ;
return ( struct SquadMeta ) { 0 } ;
return ( struct SquadMeta ) { 0 } ;
}
}
struct BoxInfo
struct BoxInfo
boxinfo ( enum BoxType type )
boxinfo ( enum BoxType type )
{
{
for ( int i = 0 ; i < ARRLEN ( boxes ) ; i + + )
for ( int i = 0 ; i < ARRLEN ( boxes ) ; i + + )
{
{
@ -190,11 +201,11 @@ boxinfo(enum BoxType type)
return boxes [ i ] ;
return boxes [ i ] ;
}
}
Log ( " No box info found for type %d \n " , type ) ;
Log ( " No box info found for type %d \n " , type ) ;
return ( struct BoxInfo ) { 0 } ;
return ( struct BoxInfo ) { 0 } ;
}
}
static sg_image
static sg_image
load_image ( const char * path )
load_image ( const char * path )
{
{
sg_image to_return = sg_alloc_image ( ) ;
sg_image to_return = sg_alloc_image ( ) ;
@ -203,10 +214,10 @@ load_image(const char *path)
int comp = 0 ;
int comp = 0 ;
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 %s image: %s\n " , path , stbi_failure_reason ( ) ) ;
exit ( - 1 ) ;
exit ( - 1 ) ;
}
}
sg_init_image ( to_return ,
sg_init_image ( to_return ,
@ -225,17 +236,17 @@ load_image(const char *path)
return to_return ;
return to_return ;
}
}
void microphone_data_callback ( ma_device * pDevice , void * pOutput , const void * pInput , ma_uint32 frameCount )
void microphone_data_callback ( ma_device * pDevice , void * pOutput , const void * pInput , ma_uint32 frameCount )
{
{
assert ( frameCount = = VOIP_EXPECTED_FRAME_COUNT ) ;
assert ( frameCount = = VOIP_EXPECTED_FRAME_COUNT ) ;
if ( peer ! = NULL )
if ( peer ! = NULL )
{
{
ma_mutex_lock ( & send_packets_mutex ) ;
ma_mutex_lock ( & send_packets_mutex ) ;
OpusPacket * packet = push_packet ( & packets_to_send ) ;
OpusPacket * packet = push_packet ( & packets_to_send ) ;
if ( packet ! = NULL )
if ( packet ! = NULL )
{
{
opus_int16 muted_audio [ VOIP_EXPECTED_FRAME_COUNT ] = { 0 } ;
opus_int16 muted_audio [ VOIP_EXPECTED_FRAME_COUNT ] = { 0 } ;
const opus_int16 * audio_buffer = ( const opus_int16 * ) pInput ;
const opus_int16 * audio_buffer = ( const opus_int16 * ) pInput ;
if ( muted )
if ( muted )
audio_buffer = muted_audio ;
audio_buffer = muted_audio ;
opus_int32 written = opus_encode ( enc , audio_buffer , VOIP_EXPECTED_FRAME_COUNT , packet - > data , VOIP_PACKET_MAX_SIZE ) ;
opus_int32 written = opus_encode ( enc , audio_buffer , VOIP_EXPECTED_FRAME_COUNT , packet - > data , VOIP_PACKET_MAX_SIZE ) ;
@ -246,18 +257,18 @@ void microphone_data_callback(ma_device *pDevice, void *pOutput, const void *pIn
( void ) pOutput ;
( void ) pOutput ;
}
}
void speaker_data_callback ( ma_device * pDevice , void * pOutput , const void * pInput , ma_uint32 frameCount )
void speaker_data_callback ( ma_device * pDevice , void * pOutput , const void * pInput , ma_uint32 frameCount )
{
{
assert ( frameCount = = VOIP_EXPECTED_FRAME_COUNT ) ;
assert ( frameCount = = VOIP_EXPECTED_FRAME_COUNT ) ;
ma_mutex_lock ( & play_packets_mutex ) ;
ma_mutex_lock ( & play_packets_mutex ) ;
OpusPacket * cur_packet = pop_packet ( & packets_to_play ) ;
OpusPacket * cur_packet = pop_packet ( & packets_to_play ) ;
if ( cur_packet ! = NULL & & cur_packet - > length > 0 ) // length of 0 means skipped packet
if ( cur_packet ! = NULL & & cur_packet - > length > 0 ) // length of 0 means skipped packet
{
{
opus_decode ( dec , cur_packet - > data , cur_packet - > length , ( opus_int16 * ) pOutput , frameCount , 0 ) ;
opus_decode ( dec , cur_packet - > data , cur_packet - > length , ( opus_int16 * ) pOutput , frameCount , 0 ) ;
}
}
else
else
{
{
opus_decode ( dec , NULL , 0 , ( opus_int16 * ) pOutput , frameCount , 0 ) ; // I think opus makes it sound good if packets are skipped with null
opus_decode ( dec , NULL , 0 , ( opus_int16 * ) pOutput , frameCount , 0 ) ; // I think opus makes it sound good if packets are skipped with null
}
}
ma_mutex_unlock ( & play_packets_mutex ) ;
ma_mutex_unlock ( & play_packets_mutex ) ;
( void ) pInput ;
( void ) pInput ;
@ -337,10 +348,10 @@ init(void)
// failure instead of exit(-1), replace the macros in sokol with this as well,
// failure instead of exit(-1), replace the macros in sokol with this as well,
// like assert
// like assert
Entity * entity_data = malloc ( sizeof * entity_data * MAX_ENTITIES ) ;
Entity * entity_data = malloc ( sizeof * entity_data * MAX_ENTITIES ) ;
initialize ( & gs , entity_data , sizeof * entity_data * MAX_ENTITIES ) ;
initialize ( & gs , entity_data , sizeof * entity_data * MAX_ENTITIES ) ;
sg_desc sgdesc = { . context = sapp_sgcontext ( ) } ;
sg_desc sgdesc = { . context = sapp_sgcontext ( ) } ;
sg_setup ( & sgdesc ) ;
sg_setup ( & sgdesc ) ;
if ( ! sg_isvalid ( ) )
if ( ! sg_isvalid ( ) )
{
{
@ -348,7 +359,7 @@ init(void)
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 ( ) )
{
{
@ -394,6 +405,9 @@ init(void)
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_available = load_image ( " loaded/flag_available.png " ) ;
image_flag_taken = load_image ( " loaded/flag_ripped.png " ) ;
image_flag_taken = load_image ( " loaded/flag_ripped.png " ) ;
image_squad_invite = load_image ( " loaded/squad_invite.png " ) ;
image_check = load_image ( " loaded/check.png " ) ;
image_no = load_image ( " loaded/no.png " ) ;
}
}
// socket initialization
// socket initialization
@ -467,7 +481,7 @@ draw_texture_rectangle_centered(V2 center, V2 width_height)
static void
static void
draw_texture_centered ( V2 center , float size )
draw_texture_centered ( V2 center , float size )
{
{
draw_texture_rectangle_centered ( center , ( V2 ) { size , size } ) ;
draw_texture_rectangle_centered ( center , ( V2 ) { size , size } ) ;
}
}
static void
static void
@ -479,22 +493,30 @@ draw_circle(V2 point, float radius)
{
{
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 ,
. y = sinf ( progress * 2.0f * PI ) * radius } ;
. y = sinf ( progress * 2.0f * PI ) * radius } ;
lines [ i ] . b = ( V2 ) { . x = cosf ( next_progress * 2.0f * PI ) * radius ,
lines [ i ] . b = ( V2 ) { . x = cosf ( next_progress * 2.0f * PI ) * radius ,
. y = sinf ( next_progress * 2.0f * PI ) * radius } ;
. y = sinf ( next_progress * 2.0f * PI ) * radius } ;
lines [ i ] . a = V2add ( lines [ i ] . a , point ) ;
lines [ i ] . a = V2add ( lines [ i ] . a , point ) ;
lines [ i ] . b = V2add ( lines [ i ] . b , point ) ;
lines [ i ] . b = V2add ( lines [ i ] . b , point ) ;
}
}
sgp_draw_lines ( lines , POINTS ) ;
sgp_draw_lines ( lines , POINTS ) ;
}
}
static Entity *
static Player * myplayer ( )
{
if ( my_player_index = = - 1 )
return NULL ;
return & gs . players [ my_player_index ] ;
}
static Entity *
myentity ( )
myentity ( )
{
{
if ( myplayer = = - 1 )
if ( myplayer ( ) = = NULL )
return NULL ;
return NULL ;
Entity * to_return = get_entity ( & gs , gs . players [ myplayer ] . entity ) ;
Entity * to_return = get_entity ( & gs , myplayer ( ) - > entity ) ;
if ( to_return ! = NULL )
if ( to_return ! = NULL )
assert ( to_return - > is_player ) ;
assert ( to_return - > is_player ) ;
return to_return ;
return to_return ;
@ -505,7 +527,9 @@ bool can_build(int i)
bool allow_building = true ;
bool allow_building = true ;
if ( boxinfo ( ( enum BoxType ) i ) . needs_tobe_unlocked )
if ( boxinfo ( ( enum BoxType ) i ) . needs_tobe_unlocked )
{
{
allow_building = gs . players [ myplayer ] . unlocked_bombs ;
allow_building = false ;
if ( myplayer ( ) ! = NULL )
allow_building = myplayer ( ) - > unlocked_bombs ;
}
}
return allow_building ;
return allow_building ;
}
}
@ -516,6 +540,26 @@ void attempt_to_build(int i)
cur_editing_boxtype = i ;
cur_editing_boxtype = i ;
}
}
static V2 screen_to_world ( float width , float height , V2 screen )
{
V2 world = screen ;
world = V2sub ( world , ( V2 ) { . x = width / 2.0f , . y = height / 2.0f } ) ;
world . x / = zoom ;
world . y / = - zoom ;
world = V2add ( world , camera_pos ) ;
return world ;
}
static V2 world_to_screen ( float width , float height , V2 world )
{
V2 screen = world ;
screen = V2sub ( screen , camera_pos ) ;
screen . x * = zoom ;
screen . y * = - zoom ;
screen = V2add ( screen , ( V2 ) { . x = width / 2.0f , . y = height / 2.0f } ) ;
return screen ;
}
static void
static void
ui ( bool draw , float dt , float width , float height )
ui ( bool draw , float dt , float width , float height )
{
{
@ -529,20 +573,127 @@ ui(bool draw, float dt, float width, float height)
if ( draw )
if ( draw )
sgp_push_transform ( ) ;
sgp_push_transform ( ) ;
// draw squad invite
static float invite_y = - 200.0f ;
static enum Squad draw_as_squad = SquadNone ;
static float yes_size = 50.0f ;
static float no_size = 50.0f ;
{
bool invited = myentity ( ) ! = NULL & & myentity ( ) - > squad_invited_to ! = SquadNone ;
float size = 200.0f ;
float yes_no_size = 50.0f ;
float x_center = 0.75f * width ;
float x = x_center - size / 2.0f ;
//AABB box = (AABB){ .x = x, .y = invite_y, .width = size, .height = size };
float yes_x = x - size / 4.0f ;
float no_x = x + size / 4.0f ;
float buttons_y = invite_y + size / 2.0f ;
bool yes_hovered = invited & & V2dist ( mouse_pos , ( V2 ) { yes_x , buttons_y } ) < yes_size / 2.0f ;
bool no_hovered = invited & & V2dist ( mouse_pos , ( V2 ) { no_x , buttons_y } ) < no_size / 2.0f ;
yes_size = lerp ( yes_size , yes_hovered ? 75.0f : 50.0f , dt * 9.0f ) ;
no_size = lerp ( no_size , no_hovered ? 75.0f : 50.0f , dt * 9.0f ) ;
if ( invited & & build_pressed & & yes_hovered ) accept_invite = true ;
if ( invited & & build_pressed & & no_hovered ) reject_invite = true ;
if ( draw )
{
invite_y = lerp ( invite_y , invited ? 50.0f : - 200.0f , dt * 5.0f ) ;
if ( invited ) draw_as_squad = myentity ( ) - > squad_invited_to ;
transform_scope {
sgp_set_pipeline ( pip ) ;
struct SquadMeta meta = squad_meta ( draw_as_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_scale_at ( 1.0f , - 1.0f , x , invite_y ) ; // images upside down by default :(
sgp_set_image ( 0 , image_squad_invite ) ;
draw_texture_centered ( ( V2 ) { x , invite_y } , size ) ;
sgp_reset_image ( 0 ) ;
sgp_reset_pipeline ( ) ;
}
// yes
transform_scope {
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
sgp_scale_at ( 1.0f , - 1.0f , yes_x , buttons_y ) ;
sgp_set_image ( 0 , image_check ) ;
draw_texture_centered ( ( V2 ) { yes_x , buttons_y } , yes_size ) ;
sgp_reset_image ( 0 ) ;
}
// no
transform_scope {
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
sgp_scale_at ( 1.0f , - 1.0f , no_x , buttons_y ) ;
sgp_set_image ( 0 , image_no ) ;
draw_texture_centered ( ( V2 ) { no_x , buttons_y } , no_size ) ;
sgp_reset_image ( 0 ) ;
}
}
}
// draw maybe inviting
{
Entity * inviting = get_entity ( & gs , maybe_inviting_this_player ) ;
if ( inviting ! = NULL & & myplayer ( ) ! = NULL )
{
V2 top_of_head = world_to_screen ( width , height , V2add ( entity_pos ( inviting ) , ( V2 ) { . y = player_scaling * PLAYER_SIZE . y / 2.0f } ) ) ;
V2 pos = V2add ( top_of_head , ( V2 ) { . y = - 30.0f } ) ;
V2 to_mouse = V2sub ( mouse_pos , world_to_screen ( width , height , entity_pos ( inviting ) ) ) ;
bool selecting_to_invite = V2dot ( V2normalize ( to_mouse ) , ( V2 ) { 0.0f , - 1.0f } ) > 0.5f & & V2length ( to_mouse ) > 15.0f ;
if ( ! mousedown [ SAPP_MOUSEBUTTON_RIGHT ] )
{
if ( selecting_to_invite )
confirm_invite_this_player = true ;
}
if ( draw )
transform_scope {
const float size = 64.0f ;
if ( selecting_to_invite )
{
sgp_set_color ( 0.5f , 0.5f , 0.5f , 0.4f ) ;
sgp_draw_filled_rect ( pos . x - size / 2.0f , pos . y - size / 2.0f , size , size ) ;
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
}
sgp_set_pipeline ( pip ) ;
struct SquadMeta meta = squad_meta ( myplayer ( ) - > 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_scale_at ( 1.0f , - 1.0f , pos . x , pos . y ) ; // images upside down by default :(
sgp_set_image ( 0 , image_squad_invite ) ;
draw_texture_centered ( pos , size ) ;
sgp_reset_image ( 0 ) ;
sgp_reset_pipeline ( ) ;
}
}
}
// draw flags
// draw flags
static V2 flag_pos [ SquadLast ] = { 0 } ;
static V2 flag_pos [ SquadLast ] = { 0 } ;
static float flag_rot [ SquadLast ] = { 0 } ;
static float flag_rot [ SquadLast ] = { 0 } ;
static float flag_scaling_increase [ SquadLast ] = { 0 } ;
static float flag_scaling_increase [ SquadLast ] = { 0 } ;
static bool choosing_flags = false ;
static bool choosing_flags = false ;
const float flag_padding = 70.0f ;
const float flag_padding = 70.0f ;
const float center_panel_height = 200.0f ;
const float center_panel_height = 200.0f ;
static float center_panel_width = 0.0f ;
static float center_panel_width = 0.0f ;
const float target_center_panel_width = ( ( SquadLast ) + 2 ) * flag_padding ;
const float target_center_panel_width = ( ( SquadLast ) + 2 ) * flag_padding ;
# define FLAG_ITER(i) for (int i = 0; i < SquadLast; i++)
# define FLAG_ITER(i) for (int i = 0; i < SquadLast; i++)
{
{
FLAG_ITER ( i )
FLAG_ITER ( i )
{
{
V2 target_pos = { 0 } ;
V2 target_pos = { 0 } ;
float target_rot = 0.0f ;
float target_rot = 0.0f ;
float flag_progress = ( float ) i / ( float ) ( SquadLast - 1.0f ) ;
float flag_progress = ( float ) i / ( float ) ( SquadLast - 1.0f ) ;
if ( choosing_flags )
if ( choosing_flags )
@ -706,7 +857,7 @@ ui(bool draw, float dt, float width, float height)
for ( int i = 0 ; i < ARRLEN ( boxes ) ; i + + )
for ( int i = 0 ; i < ARRLEN ( boxes ) ; i + + )
{
{
if ( has_point (
if ( has_point (
( AABB ) {
( AABB ) {
. x = x ,
. x = x ,
. y = y ,
. y = y ,
. width = itemframe_width ,
. width = itemframe_width ,
@ -767,7 +918,7 @@ static void draw_dots(V2 camera_pos, float gap)
{
{
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 ;
@ -778,6 +929,7 @@ static void draw_dots(V2 camera_pos, float gap)
}
}
}
}
static void
static void
frame ( void )
frame ( void )
{
{
@ -825,7 +977,7 @@ frame(void)
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 ) ;
@ -838,7 +990,7 @@ frame(void)
if ( return_value = = LZO_E_OK )
if ( return_value = = LZO_E_OK )
{
{
server_to_client_deserialize ( & msg , decompressed , decompressed_max_len , false ) ;
server_to_client_deserialize ( & msg , decompressed , decompressed_max_len , false ) ;
my player = msg . your_player ;
my _ player_index = msg . your_player ;
}
}
else
else
{
{
@ -872,17 +1024,15 @@ frame(void)
// gameplay
// gameplay
ui ( false , dt , width , height ) ; // handle events
ui ( false , dt , width , height ) ; // handle events
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 = {
V2 world_mouse_pos = screen_to_world ( width , height , mouse_pos ) ; // processed later in scope
0 } ; // keeps camera at same position after player death
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 } ;
V2 hand_pos = { 0 } ; // in local space of grid when hovering over a grid
V2 hand_pos = { 0 } ; // in local space of grid when hovering over a grid
bool hand_at_arms_length = false ;
bool hand_at_arms_length = false ;
{
{
// interpolate zoom
// interpolate zoom
@ -894,15 +1044,11 @@ frame(void)
{
{
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 . x / = zoom ;
world_mouse_pos . y / = - zoom ;
world_mouse_pos = V2add ( world_mouse_pos , ( V2 ) { . x = camera_pos . x , . y = camera_pos . y } ) ;
}
}
// 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 ( ) ) ) ;
@ -920,7 +1066,7 @@ frame(void)
hand_pos = V2add ( hand_pos , entity_pos ( myentity ( ) ) ) ;
hand_pos = V2add ( hand_pos , entity_pos ( myentity ( ) ) ) ;
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 ) {
@ -940,11 +1086,22 @@ frame(void)
}
}
}
}
// process player interaction (squad invites)
if ( interact_pressed & & myplayer ( ) ! = NULL & & myplayer ( ) - > squad ! = SquadNone )
ENTITIES_ITER ( cur )
{
if ( cur ! = myentity ( ) & & cur - > is_player & & has_point ( centered_at ( entity_pos ( cur ) , V2scale ( PLAYER_SIZE , player_scaling ) ) , world_mouse_pos ) )
{
maybe_inviting_this_player = get_id ( & gs , cur ) ;
interact_pressed = false ;
}
}
// Create and send input packet
// Create and send input packet
{
{
static size_t last_frame_id = 0 ;
static size_t last_frame_id = 0 ;
InputFrame cur_input_frame = { 0 } ;
InputFrame cur_input_frame = { 0 } ;
cur_input_frame . id = last_frame_id ;
cur_input_frame . id = last_frame_id ;
V2 input = ( V2 ) {
V2 input = ( V2 ) {
. x = ( float ) keydown [ SAPP_KEYCODE_D ] - ( float ) keydown [ SAPP_KEYCODE_A ] ,
. x = ( float ) keydown [ SAPP_KEYCODE_D ] - ( float ) keydown [ SAPP_KEYCODE_A ] ,
@ -956,7 +1113,29 @@ frame(void)
cur_input_frame . seat_action = interact_pressed ;
cur_input_frame . seat_action = interact_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 ;
if ( take_over_squad > = 0 )
{
cur_input_frame . take_over_squad = take_over_squad ;
cur_input_frame . take_over_squad = take_over_squad ;
take_over_squad = - 1 ;
}
else {
cur_input_frame . take_over_squad = - 1 ; // @Robust make this zero initialized
}
if ( confirm_invite_this_player )
{
cur_input_frame . invite_this_player = maybe_inviting_this_player ;
maybe_inviting_this_player = ( EntityID ) { 0 } ;
}
if ( accept_invite ) {
cur_input_frame . accept_cur_squad_invite = true ;
accept_invite = false ;
}
if ( reject_invite )
{
cur_input_frame . reject_cur_squad_invite = true ;
reject_invite = false ;
}
confirm_invite_this_player = false ;
if ( build_pressed & & cur_editing_boxtype ! = - 1 )
if ( build_pressed & & cur_editing_boxtype ! = - 1 )
{
{
@ -980,6 +1159,9 @@ 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 ) ;
input_differs = input_differs | | cur_input_frame . accept_cur_squad_invite ! = latest . accept_cur_squad_invite ;
input_differs = input_differs | | cur_input_frame . reject_cur_squad_invite ! = latest . reject_cur_squad_invite ;
input_differs = input_differs | | ! entityids_same ( cur_input_frame . invite_this_player , latest . invite_this_player ) ;
input_differs = input_differs | | cur_input_frame . take_over_squad ! = latest . take_over_squad ;
input_differs = input_differs | | cur_input_frame . take_over_squad ! = latest . take_over_squad ;
if ( input_differs )
if ( input_differs )
@ -1006,11 +1188,11 @@ frame(void)
{
{
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 } ;
size_t out_len = 0 ;
size_t out_len = 0 ;
if ( client_to_server_serialize ( & gs , & client_to_server , serialized , & out_len , MAX_CLIENT_TO_SERVER ) )
if ( client_to_server_serialize ( & gs , & client_to_server , serialized , & out_len , MAX_CLIENT_TO_SERVER ) )
{
{
ENetPacket * packet = enet_packet_create ( ( void * ) serialized ,
ENetPacket * packet = enet_packet_create ( ( void * ) serialized ,
out_len ,
out_len ,
ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT ) ;
ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT ) ;
enet_peer_send ( peer , 0 , packet ) ; // @Robust error check this
enet_peer_send ( peer , 0 , packet ) ; // @Robust error check this
@ -1146,17 +1328,13 @@ frame(void)
}
}
}
}
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 + + )
ENTITIES_ITER ( e )
{
{
Entity * e = & gs . entities [ i ] ;
if ( ! e - > exists )
continue ;
// draw grid
// draw grid
if ( e - > is_grid )
if ( e - > is_grid )
{
{
Entity * g = e ;
Entity * g = e ;
BOXES_ITER ( & gs , b , g )
BOXES_ITER ( & gs , b , g )
{
{
if ( b - > is_explosion_unlock )
if ( b - > is_explosion_unlock )
@ -1165,8 +1343,8 @@ frame(void)
draw_circle ( entity_pos ( b ) , GOLD_UNLOCK_RADIUS ) ;
draw_circle ( entity_pos ( b ) , GOLD_UNLOCK_RADIUS ) ;
}
}
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
// debug draw force vectors for thrusters
// debug draw force vectors for thrusters
#if 0
#if 0
{
{
if ( b - > type = = BoxThruster )
if ( b - > type = = BoxThruster )
{
{
@ -1174,7 +1352,7 @@ frame(void)
dbg_line ( entity_pos ( b ) , V2add ( entity_pos ( b ) , V2scale ( thruster_force ( b ) , - 1.0f ) ) ) ;
dbg_line ( entity_pos ( b ) , V2add ( entity_pos ( b ) , V2scale ( thruster_force ( b ) , - 1.0f ) ) ) ;
}
}
}
}
# 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 ;
@ -1239,12 +1417,12 @@ frame(void)
}
}
// draw the velocity
// draw the velocity
#if 0
#if 0
sgp_set_color ( 1.0f , 0.0f , 0.0f , 1.0f ) ;
sgp_set_color ( 1.0f , 0.0f , 0.0f , 1.0f ) ;
V2 vel = grid_vel ( g ) ;
V2 vel = grid_vel ( g ) ;
V2 to = V2add ( grid_com ( g ) , vel ) ;
V2 to = V2add ( grid_com ( g ) , vel ) ;
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
}
}
// draw player
// draw player
@ -1252,6 +1430,7 @@ frame(void)
{
{
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 ) ;
@ -1286,12 +1465,12 @@ frame(void)
sgp_translate ( SUN_POS . x , SUN_POS . y ) ;
sgp_translate ( SUN_POS . x , SUN_POS . y ) ;
set_color ( WHITE ) ;
set_color ( WHITE ) ;
sgp_set_image ( 0 , image_sun ) ;
sgp_set_image ( 0 , image_sun ) ;
draw_texture_centered ( ( V2 ) { 0 } , SUN_RADIUS * 2.0f ) ;
draw_texture_centered ( ( V2 ) { 0 } , SUN_RADIUS * 2.0f ) ;
sgp_reset_image ( 0 ) ;
sgp_reset_image ( 0 ) ;
// sun DEATH RADIUS
// sun DEATH RADIUS
set_color ( RED ) ;
set_color ( RED ) ;
draw_circle ( ( V2 ) { 0 } , INSTANT_DEATH_DISTANCE_FROM_SUN ) ;
draw_circle ( ( V2 ) { 0 } , INSTANT_DEATH_DISTANCE_FROM_SUN ) ;
}
}
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
sgp_set_color ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
@ -1303,7 +1482,7 @@ frame(void)
{
{
sgp_set_color ( 1.0f , 1.0f , 1.0f , myentity ( ) - > damage ) ;
sgp_set_color ( 1.0f , 1.0f , 1.0f , myentity ( ) - > damage ) ;
sgp_set_image ( 0 , image_low_health ) ;
sgp_set_image ( 0 , image_low_health ) ;
draw_texture_rectangle_centered ( ( V2 ) { width / 2.0f , height / 2.0f } , ( V2 ) { width , height } ) ;
draw_texture_rectangle_centered ( ( V2 ) { width / 2.0f , height / 2.0f } , ( V2 ) { width , height } ) ;
sgp_reset_image ( 0 ) ;
sgp_reset_image ( 0 ) ;
}
}
@ -1311,13 +1490,13 @@ frame(void)
ui ( true , dt , width , height ) ;
ui ( true , dt , width , height ) ;
}
}
sg_pass_action pass_action = { 0 } ;
sg_pass_action pass_action = { 0 } ;
sg_begin_default_pass ( & pass_action , ( int ) width , ( int ) height ) ;
sg_begin_default_pass ( & pass_action , ( int ) width , ( int ) height ) ;
sgp_flush ( ) ;
sgp_flush ( ) ;
sgp_end ( ) ;
sgp_end ( ) ;
sg_end_pass ( ) ;
sg_end_pass ( ) ;
sg_commit ( ) ;
sg_commit ( ) ;
}
}
void cleanup ( void )
void cleanup ( void )
{
{
@ -1346,7 +1525,7 @@ void cleanup(void)
ma_mutex_uninit ( & server_info . info_mutex ) ;
ma_mutex_uninit ( & server_info . info_mutex ) ;
}
}
void event ( const sapp_event * e )
void event ( const sapp_event * e )
{
{
switch ( e - > type )
switch ( e - > type )
{
{
@ -1399,6 +1578,8 @@ void event(const sapp_event *e)
keydown [ e - > key_code ] = false ;
keydown [ e - > key_code ] = false ;
keypressed [ e - > key_code ] . pressed = false ;
keypressed [ e - > key_code ] . pressed = false ;
keypressed [ e - > key_code ] . frame = 0 ;
keypressed [ e - > key_code ] . frame = 0 ;
}
}
break ;
break ;
@ -1407,6 +1588,7 @@ 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 :
mousedown [ e - > mouse_button ] = true ;
if ( mousepressed [ e - > mouse_button ] . frame = = 0 )
if ( mousepressed [ e - > mouse_button ] . frame = = 0 )
{
{
mousepressed [ e - > mouse_button ] . pressed = true ;
mousepressed [ e - > mouse_button ] . pressed = true ;
@ -1414,13 +1596,14 @@ void event(const sapp_event *e)
}
}
break ;
break ;
case SAPP_EVENTTYPE_MOUSE_UP :
case SAPP_EVENTTYPE_MOUSE_UP :
mousedown [ e - > mouse_button ] = false ;
mousepressed [ e - > mouse_button ] . pressed = false ;
mousepressed [ e - > mouse_button ] . pressed = false ;
mousepressed [ e - > mouse_button ] . frame = 0 ;
mousepressed [ e - > mouse_button ] . frame = 0 ;
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 )
{
{
@ -1432,7 +1615,7 @@ void event(const sapp_event *e)
}
}
sapp_desc
sapp_desc
sokol_main ( int argc , char * argv [ ] )
sokol_main ( int argc , char * argv [ ] )
{
{
bool hosting = false ;
bool hosting = false ;
stm_setup ( ) ;
stm_setup ( ) ;
@ -1440,11 +1623,11 @@ sokol_main(int argc, char *argv[])
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 ;
}
}
( void ) argv ;
( void ) argv ;
return ( sapp_desc ) {
return ( sapp_desc ) {
. init_cb = init ,
. init_cb = init ,
. frame_cb = frame ,
. frame_cb = frame ,
. cleanup_cb = cleanup ,
. cleanup_cb = cleanup ,