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 menu_try_find_cam( 3 );
379 ui_rect panel
= { 0,0, 800, 200 },
380 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
381 ui_rect_center( screen
, panel
);
382 ui_fill( panel
, GUI_COL_DARK
);
383 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
384 ui_rect_pad( panel
, (ui_px
[]){8,8} );
387 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
388 ui_font_face( &vgf_default_title
);
389 ui_text( title
, "Open Link?", 1, k_ui_align_middle_center
, 0 );
391 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
392 ui_font_face( &vgf_default_large
);
393 ui_text( title
, menu
.web_link
, 1, k_ui_align_middle_center
, 0 );
395 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 48, panel
[2], 48 };
398 ui_split_ratio( end
, k_ui_axis_v
, 2.0/3.0, 2, a
, c
);
399 ui_split_ratio( a
, k_ui_axis_v
, 1.0/2.0, 2, a
, b
);
401 i32 R
= menu_nav( &menu
.web_choice
, mh
, 2 );
403 if( menu_button( a
, R
==0, "Steam Overlay" ) )
407 ISteamFriends
*hSteamFriends
= SteamAPI_SteamFriends();
408 SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage( hSteamFriends
,
410 k_EActivateGameOverlayToWebPageMode_Default
);
411 menu
.web_link
= NULL
;
415 if( menu_button( b
, R
==1, "Web Browser" ) )
419 vg_strnull( &str
, buf
, sizeof(buf
) );
421 vg_strcat( &str
, "start " );
423 vg_strcat( &str
, "xdg-open " );
425 vg_strcat( &str
, menu
.web_link
);
427 if( vg_strgood(&str
) )
430 menu
.web_link
= NULL
;
433 if( menu_button( c
, R
==2, "No" ) || button_down( k_srbind_mback
) )
436 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
438 menu
.web_link
= NULL
;
445 if( vg
.settings_open
)
447 if( button_down( k_srbind_mback
) )
450 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
453 srinput
.state
= k_input_state_resume
;
459 if( menu
.page
== k_menu_page_credits
)
461 ui_rect panel
= { 0,0, 600, 400 },
462 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
463 ui_rect_center( screen
, panel
);
464 ui_fill( panel
, GUI_COL_DARK
);
465 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
466 ui_rect_pad( panel
, (ui_px
[]){8,8} );
469 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
470 ui_font_face( &vgf_default_title
);
471 ui_text( title
, "Skate Rift - Credits", 1, k_ui_align_middle_center
, 0 );
473 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
474 ui_font_face( &vgf_default_large
);
475 ui_text( title
, "Mt.Zero Software", 1, k_ui_align_middle_center
, 0 );
477 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
478 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
479 ui_font_face( &vgf_default_title
);
480 ui_text( title
, "Free Software", 1, k_ui_align_middle_center
, 0 );
482 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
483 ui_font_face( &vgf_default_large
);
485 "Sam Lantinga - SDL2 - libsdl.org\n"
486 "Hunter WB - Anyascii\n"
487 "David Herberth - GLAD\n"
488 "Dominic Szablewski - QOI - qoiformat.org\n"
489 "Sean Barrett - stb_image, stb_vorbis,\n"
491 "Khronos Group - OpenGL\n"
492 , 1, k_ui_align_left
, 0 );
494 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 64, panel
[2], 64 };
496 if( menu_button( end
, 1, "Back" ) || button_down( k_srbind_mback
) )
498 menu
.page
= k_menu_page_main
;
503 else if( menu
.page
== k_menu_page_starter
)
505 i32 R
= menu_nav( &menu
.intro_row
, mv
, 3 );
506 ui_rect panel
= { 0,0, 600, 400 },
507 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
508 ui_rect_center( screen
, panel
);
509 ui_fill( panel
, ui_opacity( GUI_COL_DARK
, 0.35f
) );
510 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
511 ui_rect_pad( panel
, (ui_px
[]){8,8} );
514 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
515 ui_font_face( &vgf_default_title
);
516 ui_text( title
, "Welcome to Skate Rift", 1, k_ui_align_middle_center
, 0 );
518 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
519 ui_font_face( &vgf_default_large
);
521 menu_checkbox( panel
, R
== 0,
522 "Show controls overlay (good for new players)",
523 &control_overlay
.enabled
);
524 menu_checkbox( panel
, R
== 1, "Auto connect to global server",
525 &network_client
.auto_connect
);
527 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 100, panel
[2], 100 };
528 menu_checkbox( end
, R
== 2, "Don't show this again", &menu
.skip_starter
);
529 if( menu_button( end
, R
== 3, "OK" ) )
531 menu
.page
= k_menu_page_main
;
532 skaterift
.activity
= k_skaterift_default
;
535 menu_try_find_cam( 3 );
538 else if( menu
.page
== k_menu_page_premium
)
540 i32 R
= menu_nav( &menu
.prem_row
, mh
, 1 );
541 ui_rect panel
= { 0,0, 600, 400 },
542 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
543 ui_rect_center( screen
, panel
);
544 ui_fill( panel
, ui_opacity( GUI_COL_DARK
, 0.35f
) );
545 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
546 ui_rect_pad( panel
, (ui_px
[]){8,8} );
549 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
550 ui_font_face( &vgf_default_title
);
551 ui_text( title
, "Content is in the full game.",
552 1, k_ui_align_middle_center
, 0 );
554 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
555 ui_font_face( &vgf_default_large
);
557 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 48, panel
[2], 48 }, a
,b
;
558 ui_split_ratio( end
, k_ui_axis_v
, 0.5f
, 2, a
, b
);
560 if( menu_button( a
, R
== 0, "Store Page" ) )
563 SteamAPI_ISteamFriends_ActivateGameOverlayToStore(
564 SteamAPI_SteamFriends(), 2103940, k_EOverlayToStoreFlag_None
);
567 if( menu_button( b
, R
== 1, "Nah" ) || button_down( k_srbind_mback
) )
570 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
572 skaterift
.activity
= k_skaterift_default
;
580 * -------------------------------------------------------------------*/
582 ui_font_face( &vgf_default_title
);
583 ui_px height
= vg_ui
.font
->ch
+ 16;
584 ui_rect topbar
= { 0, 0, vg
.window_x
, height
};
586 const char *opts
[] = {
587 [k_menu_main_main
] = "Menu",
588 [k_menu_main_map
] = "Map",
589 [k_menu_main_settings
] = "Settings",
590 [k_menu_main_guide
] = "Guides"
595 menu
.main_index
+= mtab
;
597 if( menu
.main_index
== -1 )
600 if( menu
.main_index
== vg_list_size(opts
) )
604 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
608 ui_px x
= 0, spacer
= 8;
609 for( u32 draw
=0; draw
<2; draw
++ )
611 if( vg_input
.display_input_method
== k_input_method_controller
)
615 ui_rect inf_lb
= { x
, 0, 32, height
};
616 ui_fill( inf_lb
, lb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
617 ui_text( inf_lb
, "\x91", 1, k_ui_align_middle_center
, 0 );
622 for( i32 i
=0; i
<vg_list_size(opts
); i
++ )
624 ui_rect box
= { x
, 0, ui_text_line_width(opts
[i
]) + 32, height
};
628 enum ui_button_state state
= ui_button_base( box
);
629 if( state
== k_ui_button_click
)
631 ui_fill( box
, GUI_COL_DARK
);
634 else if( state
== k_ui_button_holding_inside
)
636 ui_fill( box
, GUI_COL_DARK
);
638 else if( state
== k_ui_button_holding_outside
)
640 ui_fill( box
, GUI_COL_DARK
);
641 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
643 else if( state
== k_ui_button_hover
)
645 ui_fill( box
, GUI_COL_NORM
);
646 ui_outline( box
, 1, GUI_COL_ACTIVE
, 0 );
649 ui_fill( box
, i
==menu
.main_index
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
651 ui_text( box
, opts
[i
], 1, k_ui_align_middle_center
, 0 );
654 x
+= box
[2] + spacer
;
657 if( vg_input
.display_input_method
== k_input_method_controller
)
661 ui_rect inf_rb
= { x
, 0, 32, height
};
662 ui_fill( inf_rb
, rb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
663 ui_text( inf_rb
, "\x92", 1, k_ui_align_middle_center
, 0 );
669 ui_fill( (ui_rect
){ x
+8,0, vg
.window_x
-(x
+8),height
}, GUI_COL_NORM
);
672 x
= vg
.window_x
/2 - x
/2;
673 ui_fill( (ui_rect
){ 0, 0, x
-8, height
}, GUI_COL_NORM
);
677 if( menu
.main_index
== k_menu_main_map
)
680 ui_font_face( &vgf_default_large
);
681 ui_rect title
= { vg
.window_x
/2 - 512/2, height
+8, 512, 64 };
687 ui_fill( (ui_rect
){ x
,y
, 0,height
},
688 world_static
.active_instance
? GUI_COL_DARK
: GUI_COL_ACTIVE
);
692 vg_strnull( &str
, buf
, sizeof(buf
) );
693 vg_strcat( &str
, "Hub World" );
695 if( world_static
.active_instance
)
697 vg_strcat( &str
, " (" );
698 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
699 vg_strcatch( &str
, '\x06' );
700 vg_strcatch( &str
, '\x00' );
701 vg_strcat( &str
, "\x1B[0m)" );
704 ui_px w
= ui_text( (ui_rect
){ x
+8, y
, 1000, height
}, buf
, 1,
705 k_ui_align_middle_left
, 0 );
714 world_instance
*world
= &world_static
.instances
[1];
715 if( world
->status
== k_world_status_loaded
)
717 const char *world_name
=
718 mdl_pstr( &world
->meta
, world
->info
.pstr_name
);
720 vg_strnull( &str
, buf
, sizeof(buf
) );
721 vg_strcat( &str
, world_name
);
723 if( !world_static
.active_instance
&&
724 (vg_input
.display_input_method
== k_input_method_controller
) )
726 vg_strcat( &str
, " (" );
727 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
728 vg_strcatch( &str
, '\x06' );
729 vg_strcatch( &str
, '\x00' );
730 vg_strcat( &str
, "\x1B[0m)" );
733 vs
= ui_fill( (ui_rect
){ x
,y
, 1000,height
},
734 world_static
.active_instance
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
735 w
= ui_text( (ui_rect
){ x
+16,y
, 1000,height
}, buf
,
736 1, k_ui_align_middle_left
, 0 );
738 w
= w
*vg_ui
.font
->sx
+ 8*3;
741 if( button_down( k_srbind_mhub
) ||
742 ui_button_base( (ui_rect
){0,y
,x
,height
} ) == k_ui_button_click
)
744 world_switch_instance( world_static
.active_instance
^ 0x1 );
745 skaterift
.activity
= k_skaterift_default
;
746 world_map
.view_ready
= 0;
757 if( world_static
.active_instance
)
759 ui_rect stat_panel
= { x
,y
, 256,vg
.window_y
-y
};
760 u32 c0
= ui_opacity( GUI_COL_DARK
, 0.36f
);
761 struct ui_vert
*vs
= ui_fill( stat_panel
, c0
);
763 ui_rect_pad( stat_panel
, (ui_px
[2]){8,0} );
765 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_region
); i
++ )
767 ent_region
*region
= mdl_arritm( &world
->ent_region
, i
);
769 if( !region
->zone_volume
)
772 const char *title
= mdl_pstr( &world
->meta
, region
->pstr_title
);
773 ui_font_face( &vgf_default_large
);
776 menu_standard_widget( stat_panel
, title_box
, 1 );
780 ui_font_face( &vgf_default_small
);
782 ent_volume
*volume
= mdl_arritm(&world
->ent_volume
,
783 mdl_entity_id_id(region
->zone_volume
));
785 u32 combined
= k_ent_route_flag_achieve_gold
|
786 k_ent_route_flag_achieve_silver
;
791 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_route
); j
++ )
793 ent_route
*route
= mdl_arritm(&world
->ent_route
, j
);
796 m4x3_mulv( volume
->to_local
, route
->board_transform
[3], local
);
797 if( !((fabsf(local
[0]) <= 1.0f
) &&
798 (fabsf(local
[1]) <= 1.0f
) &&
799 (fabsf(local
[2]) <= 1.0f
)) )
804 combined
&= route
->flags
;
806 vg_strnull( &str
, buf
, sizeof(buf
) );
807 vg_strcat( &str
, "(Race) " );
808 vg_strcat( &str
, mdl_pstr(&world
->meta
, route
->pstr_name
));
810 if( route
->flags
& k_ent_route_flag_achieve_silver
)
811 vg_strcat( &str
, " \xb3");
812 if( route
->flags
& k_ent_route_flag_achieve_gold
)
813 vg_strcat( &str
, "\xb3");
816 ui_standard_widget( stat_panel
, r
, 1 );
817 ui_text( r
, buf
, 1, k_ui_align_middle_left
,
818 medal_colour(route
->flags
) );
821 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_challenge
); j
++ )
823 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, j
);
826 m4x3_mulv( volume
->to_local
, challenge
->transform
.co
, local
);
827 if( !((fabsf(local
[0]) <= 1.0f
) &&
828 (fabsf(local
[1]) <= 1.0f
) &&
829 (fabsf(local
[2]) <= 1.0f
)) )
834 vg_strnull( &str
, buf
, sizeof(buf
) );
835 vg_strcat( &str
, mdl_pstr(&world
->meta
, challenge
->pstr_alias
));
838 if( challenge
->status
)
840 flags
|= k_ent_route_flag_achieve_gold
;
841 flags
|= k_ent_route_flag_achieve_silver
;
842 vg_strcat( &str
, " \xb3\xb3" );
848 ui_standard_widget( stat_panel
, r
, 1 );
849 ui_text( r
, buf
, 1, k_ui_align_middle_left
, medal_colour(flags
) );
856 if( combined
& k_ent_route_flag_achieve_gold
)
857 title_col
= ui_colour( k_ui_yellow
);
858 else if( combined
& k_ent_route_flag_achieve_silver
)
859 title_col
= ui_colour( k_ui_fg
);
861 menu_heading( title_box
, title
, title_col
);
864 vs
[2].co
[1] = stat_panel
[1];
865 vs
[3].co
[1] = stat_panel
[1];
870 if( button_down( k_srbind_mback
) )
873 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
875 skaterift
.activity
= k_skaterift_default
;
879 ui_rect list0
= { vg
.window_x
/2 - 512/2, height
+32,
880 512, vg
.window_y
-height
-64 }, list
;
881 rect_copy( list0
, list
);
882 ui_rect_pad( list
, (ui_px
[2]){8,8} );
885 * -------------------------------------------------------------------*/
887 if( menu
.main_index
== k_menu_main_main
)
889 i32 R
= menu_nav( &menu
.main_row
, mv
, 2 );
891 if( menu_button( list
, R
== 0, "Resume" ) )
893 skaterift
.activity
= k_skaterift_default
;
897 if( menu_button( list
, R
== 1, "Credits" ) )
899 menu
.page
= k_menu_page_credits
;
902 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
903 if( menu_button( end
, R
== 2, "Quit Game" ) )
905 vg
.window_should_close
= 1;
908 else if( menu
.main_index
== k_menu_main_settings
)
910 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
911 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
912 i32 R
= menu_nav( &menu
.settings_row
, mv
, 8 );
914 ui_font_face( &vgf_default_large
);
916 menu_heading( list
, "Game", 0 );
917 menu_checkbox( list
, R
== 0, "Show controls overlay",
918 &control_overlay
.enabled
);
919 menu_checkbox( list
, R
== 1, "Auto connect to global server",
920 &network_client
.auto_connect
);
922 menu_heading( list
, "Audio/Video", 0 );
923 menu_slider( list
, R
== 2, "Volume", 0, 100,
924 &vg_audio
.external_global_volume
, "%.f%%" );
925 menu_slider( list
, R
== 3, "Resolution", 0, 100,
926 &k_render_scale
, "%.f%%" );
927 menu_checkbox( list
, R
== 4, "Motion Blur", &k_blur_effect
);
929 menu_heading( list
, "Camera", 0 );
930 menu_slider( list
, R
== 5, "Fov", 97, 135,
931 &k_fov
, "%.1f\xb0" );
932 menu_slider( list
, R
== 6, "Cam Height", -0.4f
, +1.4f
,
933 &k_cam_height
, vg_lerpf(-0.4f
,1.4f
,k_cam_height
)>=0.0f
?
935 menu_checkbox( list
, R
== 7, "Invert Y Axis", &k_invert_y
);
938 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
939 ui_font_face( &vgf_default_small
);
940 menu_heading( end
, "Advanced", 0 );
941 if( menu_button( end
, R
== 8, "Open Engine Settings" ) )
946 else if( menu
.main_index
== k_menu_main_guide
)
952 marg
= list0
[0]+list0
[2],
953 pw
= vg
.window_x
- marg
,
954 infx
= pw
/2 - w
/2 + marg
;
955 ui_rect inf
= { infx
, height
+32, w
, 800 };
957 struct ui_vert
*vs
= NULL
;
959 if( menu
.guide_sel
&& (menu
.guide_sel
<= 3) )
961 vs
= ui_fill( inf
, ui_opacity( GUI_COL_DARK
, 0.20f
) );
962 ui_rect_pad( inf
, (ui_px
[]){8,8} );
965 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
966 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
967 i32 R
= menu_nav( &menu
.guides_row
, mv
, 6 );
969 ui_font_face( &vgf_default_large
);
971 menu_heading( list
, "Info", 0 );
972 if( menu
.guide_sel
== 1 )
974 menu_try_find_cam( 1 );
977 ui_split( inf
, k_ui_axis_h
, 28*2, 0, title
, inf
);
978 ui_font_face( &vgf_default_title
);
979 ui_text( title
, "Where to go", 1, k_ui_align_middle_center
, 0 );
981 ui_split( inf
, k_ui_axis_h
, 28, 0, title
, inf
);
982 ui_font_face( &vgf_default_large
);
984 "Visit the sandcastles built by John Cockroach to be\n"
985 "transported into the real location. Use the map in the\n"
986 "menu to return back this hub island.\n"
988 "You can begin training at the Volcano Island, where you\n"
989 "can learn movement skills. Then travel to Mt.Zero Island\n"
990 "or Bort Downtown to test them out. Finally the most\n"
991 "challenging course can be taken on at the Valley.\n"
993 "Also visit the Steam Workshop for community made\n"
994 "locations to skate!"
995 , 1, k_ui_align_left
, 0 );
997 vs
[2].co
[1] = vs
[0].co
[1] + 84 + vgf_default_large
.sy
*11 + 16;
998 vs
[3].co
[1] = vs
[2].co
[1];
1000 if( menu_button( list
, R
== 0, "Where to go" ) ) menu
.guide_sel
= 1;
1002 if( menu
.guide_sel
== 3 )
1004 menu_try_find_cam( 2 );
1007 ui_split( inf
, k_ui_axis_h
, 28*2, 0, title
, inf
);
1008 ui_font_face( &vgf_default_title
);
1009 ui_text( title
, "Online", 1, k_ui_align_middle_center
, 0 );
1011 ui_split( inf
, k_ui_axis_h
, 28, 0, title
, inf
);
1012 ui_font_face( &vgf_default_large
);
1014 "Connection to the global server is managed by this radar\n"
1015 "dish in the hub island. Come back here to turn the\n"
1016 "connection on or off.\n"
1018 "You'll then see other players or your friends if you go\n"
1019 "to the same location, and your highscores will be saved\n"
1020 "onto the scoreboards."
1021 , 1, k_ui_align_left
, 0 );
1023 vs
[2].co
[1] = vs
[0].co
[1] + 84 + vgf_default_large
.sy
*7 + 16;
1024 vs
[3].co
[1] = vs
[2].co
[1];
1026 if( menu_button( list
, R
== 1, "Playing Online" ) ) menu
.guide_sel
= 3;
1028 menu_heading( list
, "Controls", 0 );
1029 if( menu_button( list
, R
== 2, "Skating \xb2" ) )
1033 "https://skaterift.com/index.php?page=skating" );
1035 if( menu
.guide_sel
== 0 || menu
.guide_sel
> 3 ) menu_try_find_cam( 3 );
1037 if( menu_button( list
, R
== 3, "Tricks \xb2" ) )
1041 "https://skaterift.com/index.php?page=tricks" );
1044 menu_heading( list
, "Workshop", 0 );
1045 if( menu_button( list
, R
== 4, "Create a Board \xb2" ) )
1049 "https://skaterift.com/index.php?page=workshop_board" );
1051 if( menu_button( list
, R
== 5, "Create a World \xb2" ) )
1055 "https://skaterift.com/index.php?page=workshop_world" );
1057 if( menu_button( list
, R
== 6, "Create a Playermodel \xb2" ) )
1061 "https://skaterift.com/index.php?page=workshop_player" );
1068 vg_ui
.frosting
= 0.015f
;
1069 ui_flush( k_ui_shader_colour
, vg
.window_x
, vg
.window_y
);
1070 vg_ui
.frosting
= 0.0f
;
1072 ui_font_face( &vgf_default_small
);