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
);
30 vg_tex2d_load_qoi_async_file( "textures/prem.qoi",
31 VG_TEX2D_CLAMP
|VG_TEX2D_NOMIP
|VG_TEX2D_NEAREST
,
35 void menu_open( enum menu_page page
)
37 skaterift
.activity
= k_skaterift_menu
;
39 if( page
!= k_menu_page_any
)
45 bool menu_viewing_map(void)
47 return (skaterift
.activity
== k_skaterift_menu
) &&
48 (menu
.page
== k_menu_page_main
) &&
49 (menu
.main_index
== k_menu_main_map
);
52 static void menu_decor_select( ui_rect rect
)
54 ui_context
*ctx
= ui_current_context();
55 ui_px b
= ctx
->font
->sx
, hb
= b
/2;
56 ui_rect a0
= { rect
[0] - 20 - hb
, rect
[1] + rect
[3]/2 - hb
, b
,b
},
57 a1
= { rect
[0] + rect
[2] + 20 + hb
, rect
[1] + rect
[3]/2 - hb
, b
,b
};
59 ui_text( a0
, "\x95", 1, k_ui_align_middle_center
, 0 );
60 ui_text( a1
, "\x93", 1, k_ui_align_middle_center
, 0 );
63 static void menu_standard_widget( ui_rect inout_panel
, ui_rect rect
, ui_px s
)
65 ui_split( inout_panel
, k_ui_axis_h
, ui_current_context()->font
->sy
*s
*2,
66 8, rect
, inout_panel
);
69 static bool menu_slider( ui_rect inout_panel
, bool select
, const char *label
,
70 const f32 disp_min
, const f32 disp_max
, f32
*value
,
74 menu_standard_widget( inout_panel
, rect
, 1 );
75 ui_label( rect
, label
, 1, 8, box
);
78 enum ui_button_state state
= ui_slider_base( box
, 0, 1, value
, &t
),
80 k_ui_button_holding_inside
|
81 k_ui_button_holding_outside
|
83 mask_brighter
= mask_using
| k_ui_button_hover
;
85 if( vg_input
.display_input_method
== k_input_method_controller
)
89 f32 m
= axis_state( k_sraxis_mbrowse_h
);
92 *value
+= m
* vg
.time_frame_delta
* (1.0f
/2.0f
);
93 *value
= vg_clampf( *value
, 0, 1 );
96 menu_decor_select( rect
);
97 state
|= k_ui_button_hover
;
100 state
= k_ui_button_none
;
103 ui_rect line
= { box
[0], box
[1], t
* (f32
)box
[2], box
[3] };
104 ui_fill( line
, state
&mask_brighter
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
105 ui_fill( (ui_rect
){ box
[0]+line
[2], box
[1], box
[2]-line
[2], box
[3] },
108 ui_outline( box
, 1, state
? GUI_COL_HI
: GUI_COL_ACTIVE
, 0 );
109 ui_slider_text( box
, format
, disp_min
+ (*value
)*( disp_max
-disp_min
) );
111 return (state
& mask_using
) && 1;
114 static bool menu_button( ui_rect inout_panel
, bool select
, const char *text
)
117 menu_standard_widget( inout_panel
, rect
, 1 );
119 enum ui_button_state state
= k_ui_button_none
;
121 if( vg_input
.display_input_method
== k_input_method_controller
)
125 menu_decor_select( rect
);
127 if( button_down( k_srbind_maccept
) )
128 state
= k_ui_button_click
;
133 state
= ui_button_base( rect
);
137 if( state
== k_ui_button_click
)
139 ui_fill( rect
, GUI_COL_DARK
);
141 else if( state
== k_ui_button_holding_inside
)
143 ui_fill( rect
, GUI_COL_DARK
);
145 else if( state
== k_ui_button_holding_outside
)
147 ui_fill( rect
, GUI_COL_DARK
);
148 ui_outline( rect
, 1, GUI_COL_CLICK
, 0 );
150 else if( state
== k_ui_button_hover
)
152 ui_fill( rect
, GUI_COL_ACTIVE
);
153 ui_outline( rect
, 1, GUI_COL_CLICK
, 0 );
157 ui_fill( rect
, select
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
159 ui_outline(rect
, 1, GUI_COL_HI
, 0 );
162 ui_text( rect
, text
, 1, k_ui_align_middle_center
, 0 );
164 if( state
== k_ui_button_click
)
167 audio_oneshot( &audio_ui
[0], 1.0f
, 0.0f
);
174 static bool menu_checkbox( ui_rect inout_panel
, bool select
,
175 const char *str_label
, i32
*data
)
177 ui_rect rect
, label
, box
;
178 menu_standard_widget( inout_panel
, rect
, 1 );
180 ui_split( rect
, k_ui_axis_v
, -rect
[3], 0, label
, box
);
181 ui_text( label
, str_label
, ui_current_context()->scale
,
182 k_ui_align_middle_left
, 0 );
184 enum ui_button_state state
= k_ui_button_none
;
186 if( vg_input
.display_input_method
== k_input_method_controller
)
190 menu_decor_select( rect
);
192 if( button_down( k_srbind_maccept
) )
194 *data
= (*data
) ^ 0x1;
195 state
= k_ui_button_click
;
201 state
= ui_checkbox_base( box
, data
);
205 if( state
== k_ui_button_holding_inside
)
207 ui_fill( box
, GUI_COL_ACTIVE
);
208 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
210 else if( state
== k_ui_button_holding_outside
)
212 ui_fill( box
, GUI_COL_DARK
);
213 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
215 else if( state
== k_ui_button_hover
)
217 ui_fill( box
, GUI_COL_ACTIVE
);
218 ui_outline( box
, 1, GUI_COL_HI
, 0 );
222 ui_fill( box
, select
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
223 ui_outline( box
, 1, select
? GUI_COL_HI
: GUI_COL_NORM
, 0 );
228 ui_rect_pad( box
, (ui_px
[2]){8,8} );
229 ui_fill( box
, GUI_COL_HI
);
232 if( state
== k_ui_button_click
)
235 audio_oneshot( &audio_ui
[0], 1.0f
, 0.0f
);
242 static void menu_heading( ui_rect inout_panel
, const char *label
, u32 colour
)
245 menu_standard_widget( inout_panel
, rect
, 1 );
250 u32 c0
= ui_opacity( GUI_COL_DARK
, 0.36f
),
251 c1
= ui_opacity( GUI_COL_DARK
, 0.5f
);
253 struct ui_vert
*vs
= ui_fill( rect
, c0
);
259 ui_text( rect
, label
, 1, k_ui_align_middle_center
, 1 );
262 ui_text( rect
, label
, 1, k_ui_align_middle_center
, colour
? colour
:
263 ui_colour(k_ui_blue
+k_ui_brighter
) );
266 static u32
medal_colour( u32 flags
)
268 if( flags
& k_ent_route_flag_achieve_gold
)
269 return ui_colour( k_ui_yellow
);
270 else if( flags
& k_ent_route_flag_achieve_silver
)
271 return ui_colour( k_ui_fg
);
275 static i32
menu_nav( i32
*p_row
, int mv
, i32 max
)
277 i32 row_prev
= *p_row
;
279 if( mv
< 0 ) *p_row
= vg_min( max
, (*p_row
) +1 );
280 if( mv
> 0 ) *p_row
= vg_max( 0, (*p_row
) -1 );
282 if( *p_row
!= row_prev
)
285 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
292 static void menu_try_find_cam( i32 id
)
294 world_instance
*world
= &world_static
.instances
[0];
295 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_npc
); i
++ )
297 ent_npc
*fnpc
= mdl_arritm( &world
->ent_npc
, i
);
298 if( (fnpc
->id
== 50) && (fnpc
->context
== id
) )
300 if( mdl_entity_id_type(fnpc
->camera
) == k_ent_camera
)
302 u32 index
= mdl_entity_id_id( fnpc
->camera
);
303 menu
.bg_cam
= mdl_arritm( &world
->ent_camera
, index
);
310 static void menu_link_modal( const char *url
)
314 /* Only reset the choice of browser if 'No' was selected. */
315 if( menu
.web_choice
== 2 )
321 if( button_down( k_srbind_mopen
) )
323 if( skaterift
.activity
== k_skaterift_default
)
325 menu_open( k_menu_page_main
);
330 if( skaterift
.activity
!= k_skaterift_menu
)
336 /* get buttons inputs
337 * -------------------------------------------------------------------*/
338 int ml
= button_press( k_srbind_mleft
),
339 mr
= button_press( k_srbind_mright
),
340 mu
= button_press( k_srbind_mup
),
341 md
= button_press( k_srbind_mdown
),
344 enter
= button_down( k_srbind_maccept
);
347 u8 lb_down
= 0, rb_down
= 0;
348 vg_exec_input_program( k_vg_input_type_button_u8
,
350 vg_joy_button
, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
, vg_end
352 vg_exec_input_program( k_vg_input_type_button_u8
,
354 vg_joy_button
, SDL_CONTROLLER_BUTTON_LEFTSHOULDER
, vg_end
357 int mtab
= (i32
)rb_down
- (i32
)lb_down
;
359 if( menu
.repeater
> 0.0f
)
361 menu
.repeater
-= vg_minf( vg
.time_frame_delta
, 0.5f
);
368 if( mv
|| mh
|| mtab
)
369 menu
.repeater
+= 0.2f
;
372 if( vg_input
.display_input_method
== k_input_method_kbm
)
377 if( skaterift
.activity
!= k_skaterift_menu
) return;
382 menu_try_find_cam( 3 );
384 ui_rect panel
= { 0,0, 800, 200 },
385 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
386 ui_rect_center( screen
, panel
);
387 ui_fill( panel
, GUI_COL_DARK
);
388 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
389 ui_rect_pad( panel
, (ui_px
[]){8,8} );
392 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
393 ui_font_face( &vgf_default_title
);
394 ui_text( title
, "Open Link?", 1, k_ui_align_middle_center
, 0 );
396 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
397 ui_font_face( &vgf_default_large
);
398 ui_text( title
, menu
.web_link
, 1, k_ui_align_middle_center
, 0 );
400 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 48, panel
[2], 48 };
403 ui_split_ratio( end
, k_ui_axis_v
, 2.0/3.0, 2, a
, c
);
404 ui_split_ratio( a
, k_ui_axis_v
, 1.0/2.0, 2, a
, b
);
406 i32 R
= menu_nav( &menu
.web_choice
, mh
, 2 );
408 if( menu_button( a
, R
==0, "Steam Overlay" ) )
412 ISteamFriends
*hSteamFriends
= SteamAPI_SteamFriends();
413 SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage( hSteamFriends
,
415 k_EActivateGameOverlayToWebPageMode_Default
);
416 menu
.web_link
= NULL
;
420 if( menu_button( b
, R
==1, "Web Browser" ) )
424 vg_strnull( &str
, buf
, sizeof(buf
) );
426 vg_strcat( &str
, "start " );
428 vg_strcat( &str
, "xdg-open " );
430 vg_strcat( &str
, menu
.web_link
);
432 if( vg_strgood(&str
) )
435 menu
.web_link
= NULL
;
438 if( menu_button( c
, R
==2, "No" ) || button_down( k_srbind_mback
) )
441 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
443 menu
.web_link
= NULL
;
450 if( vg
.settings_open
)
452 if( button_down( k_srbind_mback
) )
455 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
458 srinput
.state
= k_input_state_resume
;
464 if( menu
.page
== k_menu_page_credits
)
466 ui_rect panel
= { 0,0, 600, 400 },
467 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
468 ui_rect_center( screen
, panel
);
469 ui_fill( panel
, GUI_COL_DARK
);
470 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
471 ui_rect_pad( panel
, (ui_px
[]){8,8} );
474 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
475 ui_font_face( &vgf_default_title
);
476 ui_text( title
, "Skate Rift - Credits", 1, k_ui_align_middle_center
, 0 );
478 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
479 ui_font_face( &vgf_default_large
);
480 ui_text( title
, "Mt.Zero Software", 1, k_ui_align_middle_center
, 0 );
482 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
483 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
484 ui_font_face( &vgf_default_title
);
485 ui_text( title
, "Free Software", 1, k_ui_align_middle_center
, 0 );
487 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
488 ui_font_face( &vgf_default_large
);
490 "Sam Lantinga - SDL2 - libsdl.org\n"
491 "Hunter WB - Anyascii\n"
492 "David Herberth - GLAD\n"
493 "Dominic Szablewski - QOI - qoiformat.org\n"
494 "Sean Barrett - stb_image, stb_vorbis,\n"
496 "Khronos Group - OpenGL\n"
497 , 1, k_ui_align_left
, 0 );
499 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 64, panel
[2], 64 };
501 if( menu_button( end
, 1, "Back" ) || button_down( k_srbind_mback
) )
503 menu
.page
= k_menu_page_main
;
508 else if( menu
.page
== k_menu_page_starter
)
510 i32 R
= menu_nav( &menu
.intro_row
, mv
, 3 );
511 ui_rect panel
= { 0,0, 600, 400 },
512 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
513 ui_rect_center( screen
, panel
);
514 ui_fill( panel
, ui_opacity( GUI_COL_DARK
, 0.35f
) );
515 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
516 ui_rect_pad( panel
, (ui_px
[]){8,8} );
519 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
520 ui_font_face( &vgf_default_title
);
521 ui_text( title
, "Welcome to Skate Rift", 1, k_ui_align_middle_center
, 0 );
523 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
524 ui_font_face( &vgf_default_large
);
526 menu_checkbox( panel
, R
== 0,
527 "Show controls overlay (good for new players)",
528 &control_overlay
.enabled
);
529 menu_checkbox( panel
, R
== 1, "Auto connect to global server",
530 &network_client
.auto_connect
);
532 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 100, panel
[2], 100 };
533 menu_checkbox( end
, R
== 2, "Don't show this again", &menu
.skip_starter
);
534 if( menu_button( end
, R
== 3, "OK" ) )
536 menu
.page
= k_menu_page_main
;
537 skaterift
.activity
= k_skaterift_default
;
540 menu_try_find_cam( 3 );
543 else if( menu
.page
== k_menu_page_premium
)
545 i32 R
= menu_nav( &menu
.prem_row
, mh
, 1 );
546 ui_rect panel
= { 0,0, 600, 400+240 },
547 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
548 ui_rect_center( screen
, panel
);
549 ui_fill( panel
, ui_opacity( GUI_COL_DARK
, 0.35f
) );
550 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
551 ui_rect_pad( panel
, (ui_px
[]){8,8} );
554 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
555 ui_font_face( &vgf_default_title
);
556 ui_text( title
, "Content is in the full game.",
557 1, k_ui_align_middle_center
, 0 );
559 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
560 ui_font_face( &vgf_default_large
);
563 ui_split( panel
, k_ui_axis_h
, 456, 0, img
, panel
);
564 ui_image( img
, menu
.prem_tex
);
566 ui_rect end
= { panel
[0], panel
[1] + panel
[3] - 48, panel
[2], 48 }, a
,b
;
567 ui_split_ratio( end
, k_ui_axis_v
, 0.5f
, 2, a
, b
);
569 if( menu_button( a
, R
== 0, "Store Page" ) )
572 SteamAPI_ISteamFriends_ActivateGameOverlayToStore(
573 SteamAPI_SteamFriends(), 2103940, k_EOverlayToStoreFlag_None
);
576 if( menu_button( b
, R
== 1, "Nah" ) || button_down( k_srbind_mback
) )
579 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
581 skaterift
.activity
= k_skaterift_default
;
589 * -------------------------------------------------------------------*/
591 ui_font_face( &vgf_default_title
);
592 ui_px height
= ui_current_context()->font
->ch
+ 16;
593 ui_rect topbar
= { 0, 0, vg
.window_x
, height
};
595 const char *opts
[] = {
596 [k_menu_main_main
] = "Menu",
597 [k_menu_main_map
] = "Map",
598 [k_menu_main_settings
] = "Settings",
599 [k_menu_main_guide
] = "Guides"
604 menu
.main_index
+= mtab
;
606 if( menu
.main_index
== -1 )
609 if( menu
.main_index
== vg_list_size(opts
) )
613 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
617 ui_px x
= 0, spacer
= 8;
618 for( u32 draw
=0; draw
<2; draw
++ )
620 if( vg_input
.display_input_method
== k_input_method_controller
)
624 ui_rect inf_lb
= { x
, 0, 32, height
};
625 ui_fill( inf_lb
, lb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
626 ui_text( inf_lb
, "\x91", 1, k_ui_align_middle_center
, 0 );
631 for( i32 i
=0; i
<vg_list_size(opts
); i
++ )
633 ui_rect box
= { x
, 0, ui_text_line_width(opts
[i
]) + 32, height
};
637 enum ui_button_state state
= ui_button_base( box
);
638 if( state
== k_ui_button_click
)
640 ui_fill( box
, GUI_COL_DARK
);
643 else if( state
== k_ui_button_holding_inside
)
645 ui_fill( box
, GUI_COL_DARK
);
647 else if( state
== k_ui_button_holding_outside
)
649 ui_fill( box
, GUI_COL_DARK
);
650 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
652 else if( state
== k_ui_button_hover
)
654 ui_fill( box
, GUI_COL_NORM
);
655 ui_outline( box
, 1, GUI_COL_ACTIVE
, 0 );
658 ui_fill( box
, i
==menu
.main_index
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
660 ui_text( box
, opts
[i
], 1, k_ui_align_middle_center
, 0 );
663 x
+= box
[2] + spacer
;
666 if( vg_input
.display_input_method
== k_input_method_controller
)
670 ui_rect inf_rb
= { x
, 0, 32, height
};
671 ui_fill( inf_rb
, rb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
672 ui_text( inf_rb
, "\x92", 1, k_ui_align_middle_center
, 0 );
678 ui_fill( (ui_rect
){ x
+8,0, vg
.window_x
-(x
+8),height
}, GUI_COL_NORM
);
681 x
= vg
.window_x
/2 - x
/2;
682 ui_fill( (ui_rect
){ 0, 0, x
-8, height
}, GUI_COL_NORM
);
686 if( menu
.main_index
== k_menu_main_map
)
689 ui_font_face( &vgf_default_large
);
690 ui_rect title
= { vg
.window_x
/2 - 512/2, height
+8, 512, 64 };
696 ui_fill( (ui_rect
){ x
,y
, 0,height
},
697 world_static
.active_instance
? GUI_COL_DARK
: GUI_COL_ACTIVE
);
701 vg_strnull( &str
, buf
, sizeof(buf
) );
702 vg_strcat( &str
, "Hub World" );
704 if( world_static
.active_instance
)
706 vg_strcat( &str
, " (" );
707 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
708 vg_strcatch( &str
, '\x06' );
709 vg_strcatch( &str
, '\x00' );
710 vg_strcat( &str
, "\x1B[0m)" );
713 ui_px w
= ui_text( (ui_rect
){ x
+8, y
, 1000, height
}, buf
, 1,
714 k_ui_align_middle_left
, 0 );
715 w
*= ui_current_context()->font
->sx
;
723 world_instance
*world
= &world_static
.instances
[1];
724 if( world
->status
== k_world_status_loaded
)
726 const char *world_name
=
727 mdl_pstr( &world
->meta
, world
->info
.pstr_name
);
729 vg_strnull( &str
, buf
, sizeof(buf
) );
730 vg_strcat( &str
, world_name
);
732 if( !world_static
.active_instance
&&
733 (vg_input
.display_input_method
== k_input_method_controller
) )
735 vg_strcat( &str
, " (" );
736 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
737 vg_strcatch( &str
, '\x06' );
738 vg_strcatch( &str
, '\x00' );
739 vg_strcat( &str
, "\x1B[0m)" );
742 vs
= ui_fill( (ui_rect
){ x
,y
, 1000,height
},
743 world_static
.active_instance
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
744 w
= ui_text( (ui_rect
){ x
+16,y
, 1000,height
}, buf
,
745 1, k_ui_align_middle_left
, 0 );
747 w
= w
*ui_current_context()->font
->sx
+ 8*3;
750 if( button_down( k_srbind_mhub
) ||
751 ui_button_base( (ui_rect
){0,y
,x
,height
} ) == k_ui_button_click
)
753 world_switch_instance( world_static
.active_instance
^ 0x1 );
754 skaterift
.activity
= k_skaterift_default
;
755 world_map
.view_ready
= 0;
766 if( world_static
.active_instance
)
768 ui_rect stat_panel
= { x
,y
, 256,vg
.window_y
-y
};
769 u32 c0
= ui_opacity( GUI_COL_DARK
, 0.36f
);
770 struct ui_vert
*vs
= ui_fill( stat_panel
, c0
);
772 ui_rect_pad( stat_panel
, (ui_px
[2]){8,0} );
774 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_region
); i
++ )
776 ent_region
*region
= mdl_arritm( &world
->ent_region
, i
);
778 if( !region
->zone_volume
)
781 const char *title
= mdl_pstr( &world
->meta
, region
->pstr_title
);
782 ui_font_face( &vgf_default_large
);
785 menu_standard_widget( stat_panel
, title_box
, 1 );
789 ui_font_face( &vgf_default_small
);
791 ent_volume
*volume
= mdl_arritm(&world
->ent_volume
,
792 mdl_entity_id_id(region
->zone_volume
));
794 u32 combined
= k_ent_route_flag_achieve_gold
|
795 k_ent_route_flag_achieve_silver
;
800 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_route
); j
++ )
802 ent_route
*route
= mdl_arritm(&world
->ent_route
, j
);
805 m4x3_mulv( volume
->to_local
, route
->board_transform
[3], local
);
806 if( !((fabsf(local
[0]) <= 1.0f
) &&
807 (fabsf(local
[1]) <= 1.0f
) &&
808 (fabsf(local
[2]) <= 1.0f
)) )
813 combined
&= route
->flags
;
815 vg_strnull( &str
, buf
, sizeof(buf
) );
816 vg_strcat( &str
, "(Race) " );
817 vg_strcat( &str
, mdl_pstr(&world
->meta
, route
->pstr_name
));
819 if( route
->flags
& k_ent_route_flag_achieve_silver
)
820 vg_strcat( &str
, " \xb3");
821 if( route
->flags
& k_ent_route_flag_achieve_gold
)
822 vg_strcat( &str
, "\xb3");
825 ui_standard_widget( stat_panel
, r
, 1 );
826 ui_text( r
, buf
, 1, k_ui_align_middle_left
,
827 medal_colour(route
->flags
) );
830 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_challenge
); j
++ )
832 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, j
);
835 m4x3_mulv( volume
->to_local
, challenge
->transform
.co
, local
);
836 if( !((fabsf(local
[0]) <= 1.0f
) &&
837 (fabsf(local
[1]) <= 1.0f
) &&
838 (fabsf(local
[2]) <= 1.0f
)) )
843 vg_strnull( &str
, buf
, sizeof(buf
) );
844 vg_strcat( &str
, mdl_pstr(&world
->meta
, challenge
->pstr_alias
));
847 if( challenge
->status
)
849 flags
|= k_ent_route_flag_achieve_gold
;
850 flags
|= k_ent_route_flag_achieve_silver
;
851 vg_strcat( &str
, " \xb3\xb3" );
857 ui_standard_widget( stat_panel
, r
, 1 );
858 ui_text( r
, buf
, 1, k_ui_align_middle_left
, medal_colour(flags
) );
865 if( combined
& k_ent_route_flag_achieve_gold
)
866 title_col
= ui_colour( k_ui_yellow
);
867 else if( combined
& k_ent_route_flag_achieve_silver
)
868 title_col
= ui_colour( k_ui_fg
);
870 menu_heading( title_box
, title
, title_col
);
873 vs
[2].co
[1] = stat_panel
[1];
874 vs
[3].co
[1] = stat_panel
[1];
879 if( button_down( k_srbind_mback
) )
882 audio_oneshot( &audio_ui
[3], 1.0f
, 0.0f
);
884 skaterift
.activity
= k_skaterift_default
;
888 ui_rect list0
= { vg
.window_x
/2 - 512/2, height
+32,
889 512, vg
.window_y
-height
-64 }, list
;
890 rect_copy( list0
, list
);
891 ui_rect_pad( list
, (ui_px
[2]){8,8} );
894 * -------------------------------------------------------------------*/
896 if( menu
.main_index
== k_menu_main_main
)
898 i32 R
= menu_nav( &menu
.main_row
, mv
, 2 );
900 if( menu_button( list
, R
== 0, "Resume" ) )
902 skaterift
.activity
= k_skaterift_default
;
906 if( menu_button( list
, R
== 1, "Credits" ) )
908 menu
.page
= k_menu_page_credits
;
911 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
912 if( menu_button( end
, R
== 2, "Quit Game" ) )
914 vg
.window_should_close
= 1;
917 else if( menu
.main_index
== k_menu_main_settings
)
919 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
920 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
921 i32 R
= menu_nav( &menu
.settings_row
, mv
, 8 );
923 ui_font_face( &vgf_default_large
);
925 menu_heading( list
, "Game", 0 );
926 menu_checkbox( list
, R
== 0, "Show controls overlay",
927 &control_overlay
.enabled
);
928 menu_checkbox( list
, R
== 1, "Auto connect to global server",
929 &network_client
.auto_connect
);
931 menu_heading( list
, "Audio/Video", 0 );
932 menu_slider( list
, R
== 2, "Volume", 0, 100,
933 &vg_audio
.external_global_volume
, "%.f%%" );
934 menu_slider( list
, R
== 3, "Resolution", 0, 100,
935 &k_render_scale
, "%.f%%" );
936 menu_checkbox( list
, R
== 4, "Motion Blur", &k_blur_effect
);
938 menu_heading( list
, "Camera", 0 );
939 menu_slider( list
, R
== 5, "Fov", 97, 135,
940 &k_fov
, "%.1f\xb0" );
941 menu_slider( list
, R
== 6, "Cam Height", -0.4f
, +1.4f
,
942 &k_cam_height
, vg_lerpf(-0.4f
,1.4f
,k_cam_height
)>=0.0f
?
944 menu_checkbox( list
, R
== 7, "Invert Y Axis", &k_invert_y
);
947 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
948 ui_font_face( &vgf_default_small
);
949 menu_heading( end
, "Advanced", 0 );
950 if( menu_button( end
, R
== 8, "Open Engine Settings" ) )
955 else if( menu
.main_index
== k_menu_main_guide
)
961 marg
= list0
[0]+list0
[2],
962 pw
= vg
.window_x
- marg
,
963 infx
= pw
/2 - w
/2 + marg
;
964 ui_rect inf
= { infx
, height
+32, w
, 800 };
966 struct ui_vert
*vs
= NULL
;
968 if( menu
.guide_sel
&& (menu
.guide_sel
<= 3) )
970 vs
= ui_fill( inf
, ui_opacity( GUI_COL_DARK
, 0.20f
) );
971 ui_rect_pad( inf
, (ui_px
[]){8,8} );
974 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
975 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
976 i32 R
= menu_nav( &menu
.guides_row
, mv
, 6 );
978 ui_font_face( &vgf_default_large
);
980 menu_heading( list
, "Info", 0 );
981 if( menu
.guide_sel
== 1 )
983 menu_try_find_cam( 1 );
986 ui_split( inf
, k_ui_axis_h
, 28*2, 0, title
, inf
);
987 ui_font_face( &vgf_default_title
);
988 ui_text( title
, "Where to go", 1, k_ui_align_middle_center
, 0 );
990 ui_split( inf
, k_ui_axis_h
, 28, 0, title
, inf
);
991 ui_font_face( &vgf_default_large
);
993 "Visit the sandcastles built by John Cockroach to be\n"
994 "transported into the real location. Use the map in the\n"
995 "menu to return back this hub island.\n"
997 "You can begin training at the Volcano Island, where you\n"
998 "can learn movement skills. Then travel to Mt.Zero Island\n"
999 "or Bort Downtown to test them out. Finally the most\n"
1000 "challenging course can be taken on at the Valley.\n"
1002 "Also visit the Steam Workshop for community made\n"
1003 "locations to skate!"
1004 , 1, k_ui_align_left
, 0 );
1006 vs
[2].co
[1] = vs
[0].co
[1] + 84 + vgf_default_large
.sy
*11 + 16;
1007 vs
[3].co
[1] = vs
[2].co
[1];
1009 if( menu_button( list
, R
== 0, "Where to go" ) ) menu
.guide_sel
= 1;
1011 if( menu
.guide_sel
== 3 )
1013 menu_try_find_cam( 2 );
1016 ui_split( inf
, k_ui_axis_h
, 28*2, 0, title
, inf
);
1017 ui_font_face( &vgf_default_title
);
1018 ui_text( title
, "Online", 1, k_ui_align_middle_center
, 0 );
1020 ui_split( inf
, k_ui_axis_h
, 28, 0, title
, inf
);
1021 ui_font_face( &vgf_default_large
);
1023 "Connection to the global server is managed by this radar\n"
1024 "dish in the hub island. Come back here to turn the\n"
1025 "connection on or off.\n"
1027 "You'll then see other players or your friends if you go\n"
1028 "to the same location, and your highscores will be saved\n"
1029 "onto the scoreboards."
1030 , 1, k_ui_align_left
, 0 );
1032 vs
[2].co
[1] = vs
[0].co
[1] + 84 + vgf_default_large
.sy
*7 + 16;
1033 vs
[3].co
[1] = vs
[2].co
[1];
1035 if( menu_button( list
, R
== 1, "Playing Online" ) ) menu
.guide_sel
= 3;
1037 menu_heading( list
, "Controls", 0 );
1038 if( menu_button( list
, R
== 2, "Skating \xb2" ) )
1042 "https://skaterift.com/index.php?page=movement" );
1044 if( menu
.guide_sel
== 0 || menu
.guide_sel
> 3 ) menu_try_find_cam( 3 );
1046 if( menu_button( list
, R
== 3, "Tricks \xb2" ) )
1050 "https://skaterift.com/index.php?page=tricks" );
1053 menu_heading( list
, "Workshop", 0 );
1054 if( menu_button( list
, R
== 4, "Create a Board \xb2" ) )
1058 "https://skaterift.com/index.php?page=workshop_board" );
1060 if( menu_button( list
, R
== 5, "Create a World \xb2" ) )
1064 "https://skaterift.com/index.php?page=workshop_world" );
1066 if( menu_button( list
, R
== 6, "Create a Playermodel \xb2" ) )
1070 "https://skaterift.com/index.php?page=workshop_player" );
1077 g_ui_ctx
->frosting
= 0.015f
;
1078 ui_flush( k_ui_shader_colour
);
1079 g_ui_ctx
->frosting
= 0.0f
;
1081 ui_font_face( &vgf_default_small
);