8 #include "ent_miniworld.h"
12 #include "control_overlay.h"
14 #include "shaders/model_menu.h"
16 struct global_menu menu
= { .skip_starter
= 0 };
18 void menu_at_begin(void)
20 if( menu
.skip_starter
) return;
22 skaterift
.activity
= k_skaterift_menu
;
23 menu
.page
= k_menu_page_starter
;
28 vg_console_reg_var( "skip_starter_menu", &menu
.skip_starter
,
29 k_var_dtype_i32
, VG_VAR_PERSISTENT
);
32 void menu_open( enum menu_page page
)
34 skaterift
.activity
= k_skaterift_menu
;
36 if( page
!= k_menu_page_any
)
42 bool menu_viewing_map(void)
44 return (skaterift
.activity
== k_skaterift_menu
) &&
45 (menu
.page
== k_menu_page_main
) &&
46 (menu
.main_index
== k_menu_main_map
);
49 static void menu_decor_select( ui_rect rect
)
51 ui_px b
= vg_ui
.font
->sx
, hb
= b
/2;
52 ui_rect a0
= { rect
[0] - 20 - hb
, rect
[1] + rect
[3]/2 - hb
, b
,b
},
53 a1
= { rect
[0] + rect
[2] + 20 + hb
, rect
[1] + rect
[3]/2 - hb
, b
,b
};
55 ui_text( a0
, "\x95", 1, k_ui_align_middle_center
, 0 );
56 ui_text( a1
, "\x93", 1, k_ui_align_middle_center
, 0 );
59 static void menu_standard_widget( ui_rect inout_panel
, ui_rect rect
, ui_px s
)
61 ui_split( inout_panel
, k_ui_axis_h
, vg_ui
.font
->sy
*s
*2,
62 8, rect
, inout_panel
);
65 static bool menu_slider( ui_rect inout_panel
, bool select
, const char *label
,
66 const f32 disp_min
, const f32 disp_max
, f32
*value
,
70 menu_standard_widget( inout_panel
, rect
, 1 );
71 ui_label( rect
, label
, 1, 8, box
);
74 enum ui_button_state state
= ui_slider_base( box
, 0, 1, value
, &t
),
76 k_ui_button_holding_inside
|
77 k_ui_button_holding_outside
|
79 mask_brighter
= mask_using
| k_ui_button_hover
;
81 if( vg_input
.display_input_method
== k_input_method_controller
)
85 f32 m
= axis_state( k_sraxis_mbrowse_h
);
88 *value
+= m
* vg
.time_frame_delta
* (1.0f
/2.0f
);
89 *value
= vg_clampf( *value
, 0, 1 );
92 menu_decor_select( rect
);
93 state
|= k_ui_button_hover
;
96 state
= k_ui_button_none
;
99 ui_rect line
= { box
[0], box
[1], t
* (f32
)box
[2], box
[3] };
100 ui_fill( line
, state
&mask_brighter
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
101 ui_fill( (ui_rect
){ box
[0]+line
[2], box
[1], box
[2]-line
[2], box
[3] },
104 ui_outline( box
, 1, state
? GUI_COL_HI
: GUI_COL_ACTIVE
, 0 );
105 ui_slider_text( box
, format
, disp_min
+ (*value
)*( disp_max
-disp_min
) );
107 return (state
& mask_using
) && 1;
110 static bool menu_button( ui_rect inout_panel
, bool select
, const char *text
)
113 menu_standard_widget( inout_panel
, rect
, 1 );
115 enum ui_button_state state
= k_ui_button_none
;
117 if( vg_input
.display_input_method
== k_input_method_controller
)
121 menu_decor_select( rect
);
123 if( button_down( k_srbind_maccept
) )
124 state
= k_ui_button_click
;
129 state
= ui_button_base( rect
);
133 if( state
== k_ui_button_click
)
135 ui_fill( rect
, GUI_COL_DARK
);
137 else if( state
== k_ui_button_holding_inside
)
139 ui_fill( rect
, GUI_COL_DARK
);
141 else if( state
== k_ui_button_holding_outside
)
143 ui_fill( rect
, GUI_COL_DARK
);
144 ui_outline( rect
, 1, GUI_COL_CLICK
, 0 );
146 else if( state
== k_ui_button_hover
)
148 ui_fill( rect
, GUI_COL_ACTIVE
);
149 ui_outline( rect
, 1, GUI_COL_CLICK
, 0 );
153 ui_fill( rect
, select
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
155 ui_outline(rect
, 1, GUI_COL_HI
, 0 );
158 ui_text( rect
, text
, 1, k_ui_align_middle_center
, 0 );
160 if( state
== k_ui_button_click
)
163 audio_oneshot( &audio_ui
[0], 1.0f
, 0.0f
);
170 static bool menu_checkbox( ui_rect inout_panel
, bool select
,
171 const char *str_label
, i32
*data
)
173 ui_rect rect
, label
, box
;
174 menu_standard_widget( inout_panel
, rect
, 1 );
176 ui_split( rect
, k_ui_axis_v
, -rect
[3], 0, label
, box
);
177 ui_text( label
, str_label
, k_ui_scale
, k_ui_align_middle_left
, 0 );
179 enum ui_button_state state
= k_ui_button_none
;
181 if( vg_input
.display_input_method
== k_input_method_controller
)
185 menu_decor_select( rect
);
187 if( button_down( k_srbind_maccept
) )
189 *data
= (*data
) ^ 0x1;
190 state
= k_ui_button_click
;
196 state
= ui_checkbox_base( box
, data
);
200 if( state
== k_ui_button_holding_inside
)
202 ui_fill( box
, GUI_COL_ACTIVE
);
203 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
205 else if( state
== k_ui_button_holding_outside
)
207 ui_fill( box
, GUI_COL_DARK
);
208 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
210 else if( state
== k_ui_button_hover
)
212 ui_fill( box
, GUI_COL_ACTIVE
);
213 ui_outline( box
, 1, GUI_COL_HI
, 0 );
217 ui_fill( box
, select
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
218 ui_outline( box
, 1, select
? GUI_COL_HI
: GUI_COL_NORM
, 0 );
223 ui_rect_pad( box
, (ui_px
[2]){8,8} );
224 ui_fill( box
, GUI_COL_HI
);
227 if( state
== k_ui_button_click
)
230 audio_oneshot( &audio_ui
[0], 1.0f
, 0.0f
);
237 static void menu_heading( ui_rect inout_panel
, const char *label
, u32 colour
)
240 menu_standard_widget( inout_panel
, rect
, 1 );
245 u32 c0
= ui_opacity( GUI_COL_DARK
, 0.36f
),
246 c1
= ui_opacity( GUI_COL_DARK
, 0.5f
);
248 struct ui_vert
*vs
= ui_fill( rect
, c0
);
254 ui_text( rect
, label
, 1, k_ui_align_middle_center
, 1 );
257 ui_text( rect
, label
, 1, k_ui_align_middle_center
, colour
? colour
:
258 ui_colour(k_ui_blue
+k_ui_brighter
) );
261 static u32
medal_colour( u32 flags
)
263 if( flags
& k_ent_route_flag_achieve_gold
)
264 return ui_colour( k_ui_yellow
);
265 else if( flags
& k_ent_route_flag_achieve_silver
)
266 return ui_colour( k_ui_fg
);
270 static i32
menu_nav( i32
*p_row
, int mv
, i32 max
)
272 i32 row_prev
= *p_row
;
274 if( mv
< 0 ) *p_row
= vg_min( max
, (*p_row
) +1 );
275 if( mv
> 0 ) *p_row
= vg_max( 0, (*p_row
) -1 );
277 if( *p_row
!= row_prev
)
280 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
287 static void menu_try_find_cam( i32 id
)
289 world_instance
*world
= &world_static
.instances
[0];
290 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_npc
); i
++ )
292 ent_npc
*fnpc
= mdl_arritm( &world
->ent_npc
, i
);
293 if( (fnpc
->id
== 50) && (fnpc
->context
== id
) )
295 if( mdl_entity_id_type(fnpc
->camera
) == k_ent_camera
)
297 u32 index
= mdl_entity_id_id( fnpc
->camera
);
298 menu
.bg_cam
= mdl_arritm( &world
->ent_camera
, index
);
305 static void menu_link_modal( const char *url
)
309 /* Only reset the choice of browser if 'No' was selected. */
310 if( menu
.web_choice
== 2 )
316 if( button_down( k_srbind_mopen
) )
318 if( skaterift
.activity
== k_skaterift_default
)
320 menu_open( k_menu_page_main
);
325 if( skaterift
.activity
!= k_skaterift_menu
)
331 /* get buttons inputs
332 * -------------------------------------------------------------------*/
333 int ml
= button_press( k_srbind_mleft
),
334 mr
= button_press( k_srbind_mright
),
335 mu
= button_press( k_srbind_mup
),
336 md
= button_press( k_srbind_mdown
),
339 enter
= button_down( k_srbind_maccept
);
342 u8 lb_down
= 0, rb_down
= 0;
343 vg_exec_input_program( k_vg_input_type_button_u8
,
345 vg_joy_button
, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
, vg_end
347 vg_exec_input_program( k_vg_input_type_button_u8
,
349 vg_joy_button
, SDL_CONTROLLER_BUTTON_LEFTSHOULDER
, vg_end
352 int mtab
= (i32
)rb_down
- (i32
)lb_down
;
354 if( menu
.repeater
> 0.0f
)
356 menu
.repeater
-= vg_minf( vg
.time_frame_delta
, 0.5f
);
363 if( mv
|| mh
|| mtab
)
364 menu
.repeater
+= 0.2f
;
367 if( vg_input
.display_input_method
== k_input_method_kbm
)
369 vg_ui
.wants_mouse
= 1;
372 if( skaterift
.activity
!= k_skaterift_menu
) return;
377 ui_rect panel
= { 0,0, 800, 200 },
378 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
379 ui_rect_center( screen
, panel
);
380 ui_fill( panel
, GUI_COL_DARK
);
381 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
382 ui_rect_pad( panel
, (ui_px
[]){8,8} );
385 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
386 ui_font_face( &vgf_default_title
);
387 ui_text( title
, "Open Link?", 1, k_ui_align_middle_center
, 0 );
389 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
390 ui_font_face( &vgf_default_large
);
391 ui_text( title
, menu
.web_link
, 1, k_ui_align_middle_center
, 0 );
393 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 48, panel
[2], 48 };
396 ui_split_ratio( end
, k_ui_axis_v
, 2.0/3.0, 2, a
, c
);
397 ui_split_ratio( a
, k_ui_axis_v
, 1.0/2.0, 2, a
, b
);
399 i32 R
= menu_nav( &menu
.web_choice
, mh
, 2 );
401 if( menu_button( a
, R
==0, "Steam Overlay" ) )
405 ISteamFriends
*hSteamFriends
= SteamAPI_SteamFriends();
406 SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage( hSteamFriends
,
408 k_EActivateGameOverlayToWebPageMode_Default
);
409 menu
.web_link
= NULL
;
413 if( menu_button( b
, R
==1, "Web Browser" ) )
417 vg_strnull( &str
, buf
, sizeof(buf
) );
419 vg_strcat( &str
, "start " );
421 vg_strcat( &str
, "xdg-open " );
423 vg_strcat( &str
, menu
.web_link
);
425 if( vg_strgood(&str
) )
428 menu
.web_link
= NULL
;
431 if( menu_button( c
, R
==2, "No" ) || button_down( k_srbind_mback
) )
434 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
436 menu
.web_link
= NULL
;
443 if( vg
.settings_open
)
445 if( button_down( k_srbind_mback
) )
448 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
451 srinput
.state
= k_input_state_resume
;
457 if( menu
.page
== k_menu_page_credits
)
459 ui_rect panel
= { 0,0, 600, 400 },
460 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
461 ui_rect_center( screen
, panel
);
462 ui_fill( panel
, GUI_COL_DARK
);
463 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
464 ui_rect_pad( panel
, (ui_px
[]){8,8} );
467 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
468 ui_font_face( &vgf_default_title
);
469 ui_text( title
, "Skate Rift - Credits", 1, k_ui_align_middle_center
, 0 );
471 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
472 ui_font_face( &vgf_default_large
);
473 ui_text( title
, "Mt.Zero Software", 1, k_ui_align_middle_center
, 0 );
475 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
476 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
477 ui_font_face( &vgf_default_title
);
478 ui_text( title
, "Free Software", 1, k_ui_align_middle_center
, 0 );
480 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
481 ui_font_face( &vgf_default_large
);
483 "Sam Lantinga - SDL2 - libsdl.org\n"
484 "Hunter WB - Anyascii\n"
485 "David Herberth - GLAD\n"
486 "Dominic Szablewski - QOI - qoiformat.org\n"
487 "Sean Barrett - stb_image, stb_vorbis,\n"
489 "Khronos Group - OpenGL\n"
490 , 1, k_ui_align_left
, 0 );
492 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 64, panel
[2], 64 };
494 if( menu_button( end
, 1, "Back" ) || button_down( k_srbind_mback
) )
496 menu
.page
= k_menu_page_main
;
501 else if( menu
.page
== k_menu_page_starter
)
503 i32 R
= menu_nav( &menu
.intro_row
, mv
, 3 );
504 ui_rect panel
= { 0,0, 600, 400 },
505 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
506 ui_rect_center( screen
, panel
);
507 ui_fill( panel
, ui_opacity( GUI_COL_DARK
, 0.35f
) );
508 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
509 ui_rect_pad( panel
, (ui_px
[]){8,8} );
512 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
513 ui_font_face( &vgf_default_title
);
514 ui_text( title
, "Welcome to Skate Rift", 1, k_ui_align_middle_center
, 0 );
516 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
517 ui_font_face( &vgf_default_large
);
519 menu_checkbox( panel
, R
== 0,
520 "Show controls overlay (good for new players)",
521 &control_overlay
.enabled
);
522 menu_checkbox( panel
, R
== 1, "Auto connect to global server",
523 &network_client
.auto_connect
);
525 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 100, panel
[2], 100 };
526 menu_checkbox( end
, R
== 2, "Don't show this again", &menu
.skip_starter
);
527 if( menu_button( end
, R
== 3, "OK" ) )
529 menu
.page
= k_menu_page_main
;
530 skaterift
.activity
= k_skaterift_default
;
533 menu_try_find_cam( 3 );
536 else if( menu
.page
== k_menu_page_premium
)
538 i32 R
= menu_nav( &menu
.prem_row
, mh
, 1 );
539 ui_rect panel
= { 0,0, 600, 400 },
540 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
541 ui_rect_center( screen
, panel
);
542 ui_fill( panel
, ui_opacity( GUI_COL_DARK
, 0.35f
) );
543 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
544 ui_rect_pad( panel
, (ui_px
[]){8,8} );
547 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
548 ui_font_face( &vgf_default_title
);
549 ui_text( title
, "Content is in the full game.",
550 1, k_ui_align_middle_center
, 0 );
552 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
553 ui_font_face( &vgf_default_large
);
555 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 48, panel
[2], 48 }, a
,b
;
556 ui_split_ratio( end
, k_ui_axis_v
, 0.5f
, 2, a
, b
);
558 if( menu_button( a
, R
== 0, "Store Page" ) )
561 SteamAPI_ISteamFriends_ActivateGameOverlayToStore(
562 SteamAPI_SteamFriends(), 2103940, k_EOverlayToStoreFlag_None
);
565 if( menu_button( b
, R
== 1, "Nah" ) || button_down( k_srbind_mback
) )
568 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
570 skaterift
.activity
= k_skaterift_default
;
578 * -------------------------------------------------------------------*/
580 ui_font_face( &vgf_default_title
);
581 ui_px height
= vg_ui
.font
->ch
+ 16;
582 ui_rect topbar
= { 0, 0, vg
.window_x
, height
};
584 const char *opts
[] = {
585 [k_menu_main_main
] = "Menu",
586 [k_menu_main_map
] = "Map",
587 [k_menu_main_settings
] = "Settings",
588 [k_menu_main_guide
] = "Guides"
593 menu
.main_index
+= mtab
;
595 if( menu
.main_index
== -1 )
598 if( menu
.main_index
== vg_list_size(opts
) )
602 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
606 ui_px x
= 0, spacer
= 8;
607 for( u32 draw
=0; draw
<2; draw
++ )
609 if( vg_input
.display_input_method
== k_input_method_controller
)
613 ui_rect inf_lb
= { x
, 0, 32, height
};
614 ui_fill( inf_lb
, lb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
615 ui_text( inf_lb
, "\x91", 1, k_ui_align_middle_center
, 0 );
620 for( i32 i
=0; i
<vg_list_size(opts
); i
++ )
622 ui_rect box
= { x
, 0, ui_text_line_width(opts
[i
]) + 32, height
};
626 enum ui_button_state state
= ui_button_base( box
);
627 if( state
== k_ui_button_click
)
629 ui_fill( box
, GUI_COL_DARK
);
632 else if( state
== k_ui_button_holding_inside
)
634 ui_fill( box
, GUI_COL_DARK
);
636 else if( state
== k_ui_button_holding_outside
)
638 ui_fill( box
, GUI_COL_DARK
);
639 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
641 else if( state
== k_ui_button_hover
)
643 ui_fill( box
, GUI_COL_NORM
);
644 ui_outline( box
, 1, GUI_COL_ACTIVE
, 0 );
647 ui_fill( box
, i
==menu
.main_index
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
649 ui_text( box
, opts
[i
], 1, k_ui_align_middle_center
, 0 );
652 x
+= box
[2] + spacer
;
655 if( vg_input
.display_input_method
== k_input_method_controller
)
659 ui_rect inf_rb
= { x
, 0, 32, height
};
660 ui_fill( inf_rb
, rb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
661 ui_text( inf_rb
, "\x92", 1, k_ui_align_middle_center
, 0 );
667 ui_fill( (ui_rect
){ x
+8,0, vg
.window_x
-(x
+8),height
}, GUI_COL_NORM
);
670 x
= vg
.window_x
/2 - x
/2;
671 ui_fill( (ui_rect
){ 0, 0, x
-8, height
}, GUI_COL_NORM
);
675 if( menu
.main_index
== k_menu_main_map
)
678 ui_font_face( &vgf_default_large
);
679 ui_rect title
= { vg
.window_x
/2 - 512/2, height
+8, 512, 64 };
685 ui_fill( (ui_rect
){ x
,y
, 0,height
},
686 world_static
.active_instance
? GUI_COL_DARK
: GUI_COL_ACTIVE
);
690 vg_strnull( &str
, buf
, sizeof(buf
) );
691 vg_strcat( &str
, "Hub World" );
693 if( world_static
.active_instance
)
695 vg_strcat( &str
, " (" );
696 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
697 vg_strcatch( &str
, '\x06' );
698 vg_strcatch( &str
, '\x00' );
699 vg_strcat( &str
, "\x1B[0m)" );
702 ui_px w
= ui_text( (ui_rect
){ x
+8, y
, 1000, height
}, buf
, 1,
703 k_ui_align_middle_left
, 0 );
712 world_instance
*world
= &world_static
.instances
[1];
713 if( world
->status
== k_world_status_loaded
)
715 const char *world_name
=
716 mdl_pstr( &world
->meta
, world
->info
.pstr_name
);
718 vg_strnull( &str
, buf
, sizeof(buf
) );
719 vg_strcat( &str
, world_name
);
721 if( !world_static
.active_instance
&&
722 (vg_input
.display_input_method
== k_input_method_controller
) )
724 vg_strcat( &str
, " (" );
725 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
726 vg_strcatch( &str
, '\x06' );
727 vg_strcatch( &str
, '\x00' );
728 vg_strcat( &str
, "\x1B[0m)" );
731 vs
= ui_fill( (ui_rect
){ x
,y
, 1000,height
},
732 world_static
.active_instance
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
733 w
= ui_text( (ui_rect
){ x
+16,y
, 1000,height
}, buf
,
734 1, k_ui_align_middle_left
, 0 );
736 w
= w
*vg_ui
.font
->sx
+ 8*3;
739 if( button_down( k_srbind_mhub
) ||
740 ui_button_base( (ui_rect
){0,y
,x
,height
} ) == k_ui_button_click
)
742 world_switch_instance( world_static
.active_instance
^ 0x1 );
743 skaterift
.activity
= k_skaterift_default
;
744 world_map
.view_ready
= 0;
755 if( world_static
.active_instance
)
757 ui_rect stat_panel
= { x
,y
, 256,vg
.window_y
-y
};
758 u32 c0
= ui_opacity( GUI_COL_DARK
, 0.36f
);
759 struct ui_vert
*vs
= ui_fill( stat_panel
, c0
);
761 ui_rect_pad( stat_panel
, (ui_px
[2]){8,0} );
763 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_region
); i
++ )
765 ent_region
*region
= mdl_arritm( &world
->ent_region
, i
);
767 if( !region
->zone_volume
)
770 const char *title
= mdl_pstr( &world
->meta
, region
->pstr_title
);
771 ui_font_face( &vgf_default_large
);
774 menu_standard_widget( stat_panel
, title_box
, 1 );
778 ui_font_face( &vgf_default_small
);
780 ent_volume
*volume
= mdl_arritm(&world
->ent_volume
,
781 mdl_entity_id_id(region
->zone_volume
));
783 u32 combined
= k_ent_route_flag_achieve_gold
|
784 k_ent_route_flag_achieve_silver
;
789 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_route
); j
++ )
791 ent_route
*route
= mdl_arritm(&world
->ent_route
, j
);
794 m4x3_mulv( volume
->to_local
, route
->board_transform
[3], local
);
795 if( !((fabsf(local
[0]) <= 1.0f
) &&
796 (fabsf(local
[1]) <= 1.0f
) &&
797 (fabsf(local
[2]) <= 1.0f
)) )
802 combined
&= route
->flags
;
804 vg_strnull( &str
, buf
, sizeof(buf
) );
805 vg_strcat( &str
, "(Race) " );
806 vg_strcat( &str
, mdl_pstr(&world
->meta
, route
->pstr_name
));
808 if( route
->flags
& k_ent_route_flag_achieve_silver
)
809 vg_strcat( &str
, " \xb3");
810 if( route
->flags
& k_ent_route_flag_achieve_gold
)
811 vg_strcat( &str
, "\xb3");
814 ui_standard_widget( stat_panel
, r
, 1 );
815 ui_text( r
, buf
, 1, k_ui_align_middle_left
,
816 medal_colour(route
->flags
) );
819 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_challenge
); j
++ )
821 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, j
);
824 m4x3_mulv( volume
->to_local
, challenge
->transform
.co
, local
);
825 if( !((fabsf(local
[0]) <= 1.0f
) &&
826 (fabsf(local
[1]) <= 1.0f
) &&
827 (fabsf(local
[2]) <= 1.0f
)) )
832 vg_strnull( &str
, buf
, sizeof(buf
) );
833 vg_strcat( &str
, mdl_pstr(&world
->meta
, challenge
->pstr_alias
));
836 if( challenge
->status
)
838 flags
|= k_ent_route_flag_achieve_gold
;
839 flags
|= k_ent_route_flag_achieve_silver
;
840 vg_strcat( &str
, " \xb3\xb3" );
846 ui_standard_widget( stat_panel
, r
, 1 );
847 ui_text( r
, buf
, 1, k_ui_align_middle_left
, medal_colour(flags
) );
854 if( combined
& k_ent_route_flag_achieve_gold
)
855 title_col
= ui_colour( k_ui_yellow
);
856 else if( combined
& k_ent_route_flag_achieve_silver
)
857 title_col
= ui_colour( k_ui_fg
);
859 menu_heading( title_box
, title
, title_col
);
862 vs
[2].co
[1] = stat_panel
[1];
863 vs
[3].co
[1] = stat_panel
[1];
868 if( button_down( k_srbind_mback
) )
871 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
873 skaterift
.activity
= k_skaterift_default
;
877 ui_rect list0
= { vg
.window_x
/2 - 512/2, height
+32,
878 512, vg
.window_y
-height
-64 }, list
;
879 rect_copy( list0
, list
);
880 ui_rect_pad( list
, (ui_px
[2]){8,8} );
883 * -------------------------------------------------------------------*/
885 if( menu
.main_index
== k_menu_main_main
)
887 i32 R
= menu_nav( &menu
.main_row
, mv
, 2 );
889 if( menu_button( list
, R
== 0, "Resume" ) )
891 skaterift
.activity
= k_skaterift_default
;
895 if( menu_button( list
, R
== 1, "Credits" ) )
897 menu
.page
= k_menu_page_credits
;
900 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
901 if( menu_button( end
, R
== 2, "Quit Game" ) )
903 vg
.window_should_close
= 1;
906 else if( menu
.main_index
== k_menu_main_settings
)
908 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
909 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
910 i32 R
= menu_nav( &menu
.settings_row
, mv
, 8 );
912 ui_font_face( &vgf_default_large
);
914 menu_heading( list
, "Game", 0 );
915 menu_checkbox( list
, R
== 0, "Show controls overlay",
916 &control_overlay
.enabled
);
917 menu_checkbox( list
, R
== 1, "Auto connect to global server",
918 &network_client
.auto_connect
);
920 menu_heading( list
, "Audio/Video", 0 );
921 menu_slider( list
, R
== 2, "Volume", 0, 100,
922 &vg_audio
.external_global_volume
, "%.f%%" );
923 menu_slider( list
, R
== 3, "Resolution", 0, 100,
924 &k_render_scale
, "%.f%%" );
925 menu_checkbox( list
, R
== 4, "Motion Blur", &k_blur_effect
);
927 menu_heading( list
, "Camera", 0 );
928 menu_slider( list
, R
== 5, "Fov", 97, 135,
929 &k_fov
, "%.1f\xb0" );
930 menu_slider( list
, R
== 6, "Cam Height", -0.4f
, +1.4f
,
931 &k_cam_height
, vg_lerpf(-0.4f
,1.4f
,k_cam_height
)>=0.0f
?
933 menu_checkbox( list
, R
== 7, "Invert Y Axis", &k_invert_y
);
936 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
937 ui_font_face( &vgf_default_small
);
938 menu_heading( end
, "Advanced", 0 );
939 if( menu_button( end
, R
== 8, "Open Engine Settings" ) )
944 else if( menu
.main_index
== k_menu_main_guide
)
949 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
950 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
951 i32 R
= menu_nav( &menu
.guides_row
, mv
, 7 );
953 ui_font_face( &vgf_default_large
);
955 menu_heading( list
, "Info", 0 );
956 if( menu_button( list
, R
== 0, "Where to go" ) ) menu
.guide_sel
= 1;
957 if( menu
.guide_sel
== 1 ) menu_try_find_cam( 1 );
959 if( menu_button( list
, R
== 1, "Finding worlds" ) ) menu
.guide_sel
= 2;
960 if( menu
.guide_sel
== 2 ) menu_try_find_cam( 0 );
962 if( menu_button( list
, R
== 2, "Playing Online" ) ) menu
.guide_sel
= 3;
963 if( menu
.guide_sel
== 3 ) menu_try_find_cam( 2 );
965 menu_heading( list
, "Controls", 0 );
966 if( menu_button( list
, R
== 3, "Skating \xb2" ) )
969 "https://skaterift.com/index.php?page=skating" );
971 if( menu
.guide_sel
== 0 || menu
.guide_sel
> 3 ) menu_try_find_cam( 3 );
973 if( menu_button( list
, R
== 4, "Tricks \xb2" ) )
976 "https://skaterift.com/index.php?page=tricks" );
979 menu_heading( list
, "Workshop", 0 );
980 if( menu_button( list
, R
== 5, "Create a Board \xb2" ) )
983 "https://skaterift.com/index.php?page=workshop_board" );
985 if( menu_button( list
, R
== 6, "Create a World \xb2" ) )
988 "https://skaterift.com/index.php?page=workshop_world" );
990 if( menu_button( list
, R
== 7, "Create a Playermodel \xb2" ) )
993 "https://skaterift.com/index.php?page=workshop_player" );
1000 vg_ui
.frosting
= 0.015f
;
1001 ui_flush( k_ui_shader_colour
, vg
.window_x
, vg
.window_y
);
1002 vg_ui
.frosting
= 0.0f
;
1004 ui_font_face( &vgf_default_small
);