@ -34,7 +34,7 @@
static sg_pipeline pip ;
static struct GameState gs = { 0 } ;
static int my player = - 1 ;
static int my _ player_index = - 1 ;
static bool right_mouse_down = false ;
# define MAX_KEYDOWN SAPP_KEYCODE_MENU
static bool keydown [ MAX_KEYDOWN ] = { 0 } ;
@ -49,13 +49,20 @@ static bool fullscreened = false;
static bool build_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
{
bool pressed ;
uint64_t frame ;
} MousePressed ;
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 float funval = 0.0f ; // easy to play with value controlled by left mouse button when held
@ -83,6 +90,9 @@ static sg_image image_low_health;
static sg_image image_mic_muted ;
static sg_image image_flag_available ;
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_rotation = 0 ;
@ -140,6 +150,7 @@ static struct BoxInfo
. 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))
static struct SquadMeta
@ -206,7 +217,7 @@ load_image(const char *path)
stbi_uc * image_data = stbi_load ( path , & x , & y , & comp , desired_channels ) ;
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 ) ;
}
sg_init_image ( to_return ,
@ -394,6 +405,9 @@ init(void)
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 " ) ;
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
@ -489,12 +503,20 @@ draw_circle(V2 point, float radius)
sgp_draw_lines ( lines , POINTS ) ;
}
static Player * myplayer ( )
{
if ( my_player_index = = - 1 )
return NULL ;
return & gs . players [ my_player_index ] ;
}
static Entity *
myentity ( )
{
if ( myplayer = = - 1 )
if ( myplayer ( ) = = 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 )
assert ( to_return - > is_player ) ;
return to_return ;
@ -505,7 +527,9 @@ bool can_build(int i)
bool allow_building = true ;
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 ;
}
@ -516,6 +540,26 @@ void attempt_to_build(int 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
ui ( bool draw , float dt , float width , float height )
{
@ -529,6 +573,113 @@ ui(bool draw, float dt, float width, float height)
if ( draw )
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
static V2 flag_pos [ SquadLast ] = { 0 } ;
static float flag_rot [ SquadLast ] = { 0 } ;
@ -778,6 +929,7 @@ static void draw_dots(V2 camera_pos, float gap)
}
}
static void
frame ( void )
{
@ -838,7 +990,7 @@ frame(void)
if ( return_value = = LZO_E_OK )
{
server_to_client_deserialize ( & msg , decompressed , decompressed_max_len , false ) ;
my player = msg . your_player ;
my _ player_index = msg . your_player ;
}
else
{
@ -874,9 +1026,7 @@ frame(void)
ui ( false , dt , width , height ) ; // handle events
V2 build_target_pos = { 0 } ;
float build_target_rotation = 0.0f ;
static V2 camera_pos = {
0 } ; // keeps camera at same position after player death
V2 world_mouse_pos = mouse_pos ; // processed later in scope
V2 world_mouse_pos = screen_to_world ( width , height , mouse_pos ) ; // processed later in scope
struct BuildPreviewInfo
{
V2 grid_pos ;
@ -894,10 +1044,6 @@ frame(void)
{
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
@ -940,6 +1086,17 @@ 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
{
@ -956,7 +1113,29 @@ frame(void)
cur_input_frame . seat_action = interact_pressed ;
cur_input_frame . grid_hand_pos_local_to = grid_to_build_on ;
cur_input_frame . hand_pos = possibly_local_hand_pos ;
if ( take_over_squad > = 0 )
{
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 )
{
@ -980,6 +1159,9 @@ frame(void)
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 | | 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 ;
if ( input_differs )
@ -1146,13 +1328,9 @@ frame(void)
}
}
static float player_scaling = 1.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
if ( e - > is_grid )
{
@ -1252,6 +1430,7 @@ frame(void)
{
transform_scope
{
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 ) ;
@ -1399,6 +1578,8 @@ void event(const sapp_event *e)
keydown [ e - > key_code ] = false ;
keypressed [ e - > key_code ] . pressed = false ;
keypressed [ e - > key_code ] . frame = 0 ;
}
break ;
@ -1407,6 +1588,7 @@ void event(const sapp_event *e)
zoom_target = clamp ( zoom_target , 0.5f , 900.0f ) ;
break ;
case SAPP_EVENTTYPE_MOUSE_DOWN :
mousedown [ e - > mouse_button ] = true ;
if ( mousepressed [ e - > mouse_button ] . frame = = 0 )
{
mousepressed [ e - > mouse_button ] . pressed = true ;
@ -1414,6 +1596,7 @@ void event(const sapp_event *e)
}
break ;
case SAPP_EVENTTYPE_MOUSE_UP :
mousedown [ e - > mouse_button ] = false ;
mousepressed [ e - > mouse_button ] . pressed = false ;
mousepressed [ e - > mouse_button ] . frame = 0 ;
break ;