_compass.sm_comp_person = mdl_get_submesh_index( mdl, "comp_person" );
_compass.sm_comp_s = mdl_get_submesh_index( mdl, "comp_s" );
_compass.sm_comp_w = mdl_get_submesh_index( mdl, "comp_w" );
+ _compass.sm_comp_objective = mdl_get_submesh_index( mdl, "comp_objective" );
mdl_close( mdl );
vg_console_reg_var( "compass_alpha", &_compass.alpha, k_var_dtype_f32, VG_VAR_PERSISTENT );
/* TODO: Players and friends */
shader_compass_uColour( (v4f){ 1,1,1,1 } );
+ if( network_connected() )
+ {
+ for( u32 i=0; i<NETWORK_MAX_PLAYERS; i ++ )
+ {
+ struct network_player *player = &netplayers.list[i];
+ if( player->active && player->same_world )
+ {
+ struct skeleton *sk = &localplayer.skeleton;
+ m4x3f *final_mtx = &netplayers.final_mtx[ sk->bone_count*i ];
+
+ if( compass_co( projection, final_mtx[0][3], 0.0f ) )
+ mdl_draw_submesh( &mdl->submeshes[ player->isfriend? _compass.sm_comp_friend: _compass.sm_comp_person ] );
+ }
+ }
+ }
+
world_instance *world = &_world.main;
/* story markers */
mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_notify ] );
}
}
+ for( u32 i=0; i<af_arrcount(&world->ent_challenge); i++ )
+ {
+ ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
+ if( challenge->flags & k_ent_challenge_locked )
+ continue;
+ if( !challenge->status )
+ {
+ if( compass_co( projection, challenge->transform.co, 0.0f ) )
+ mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_objective ] );
+ }
+ }
/* gates n shit */
f32 t = (_world.time - _world.last_gate_hit_time) / 30.0f;
{
ent_route *route = af_arritm( &world->ent_route, i );
+ if( !(route->flags & (k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver)) )
+ {
+ if( compass_co( projection, route->board_transform[3], 0.0f ) )
+ mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_objective ] );
+ }
+
if( route->active_checkpoint != 0xffff )
{
v4f colour;
sm_comp_notify,
sm_comp_person,
sm_comp_s,
- sm_comp_w;
+ sm_comp_w,
+ sm_comp_objective;
f32 alpha;
}
ui_capture_mouse(ctx, 1);
ui_rect leaderboard_box = { ref_box[0], ref_box[1] + ref_box[3] + 16, ref_box[2], 24 };
-
- if( !network_connected() )
+
+ world_instance *world = &_world.main;
+ if( route_index >= af_arrcount( &world->ent_route ) )
{
ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
- ui_text( ctx, leaderboard_box, "Offline - No Leaderboards", 1, k_ui_align_middle_center, 0 );
+ ui_text( ctx, leaderboard_box, "Error - Out of range", 1, k_ui_align_middle_center, 0 );
return;
}
- world_instance *world = &_world.main;
- if( route_index >= af_arrcount( &world->ent_route ) )
+ ent_route *route = af_arritm( &world->ent_route, route_index );
+ ui_rect right_box = { leaderboard_box[0] + leaderboard_box[2] + 16, leaderboard_box[1], 300, 100 };
+ ui_rect title_box;
+ ui_fill( ctx, right_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
+ ctx->font = &vgf_default_title;
+ ui_split( right_box, k_ui_axis_h, 48, 2, title_box, right_box );
+ ui_text( ctx, title_box, "Completion", 1, k_ui_align_middle_center, 0 );
+
+ ctx->font = &vgf_default_large;
+
+ if( route->flags & k_ent_route_flag_achieve_gold )
+ ui_text( ctx, right_box, "Completed in Gold!", 1, k_ui_align_middle_center, 0 );
+ else if( route->flags & k_ent_route_flag_achieve_silver )
+ ui_text( ctx, right_box, "Completed in Silver\n(Don't fall for gold)", 1, k_ui_align_middle_center, 0 );
+ else
+ ui_text( ctx, right_box, "Not completed...", 1, k_ui_align_middle_center, 0 );
+
+
+ if( !network_connected() )
{
ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) );
- ui_text( ctx, leaderboard_box, "Error - Out of range", 1, k_ui_align_middle_center, 0 );
+ ui_text( ctx, leaderboard_box, "Offline - No Leaderboards", 1, k_ui_align_middle_center, 0 );
return;
}
if( (delta > 45.0) || (board->cache_time == 0.0) )
{
board->cache_time = vg.time_real;
- ent_route *route = af_arritm( &world->ent_route, route_index );
char mod_uid[ ADDON_UID_MAX ];
addon_uid( _world.main.addon_id, mod_uid );
network_request_scoreboard( mod_uid, af_str( &world->meta.af, route->pstr_name ),
#define GUI_COL_HI ui_opacity( 0x00ffffff, 0.8f )
enum gui_icon {
- k_gui_icon_tick = 0,
- k_gui_icon_tick_2d,
+ k_gui_icon_tick1 = 0,
+ k_gui_icon_tick2,
+ k_gui_icon_run,
+ k_gui_icon_challenge,
k_gui_icon_exclaim,
- k_gui_icon_exclaim_2d,
k_gui_icon_board,
k_gui_icon_world,
k_gui_icon_rift,
/* helpers
* ----------------------------------------------------------------- */
- gui.factive = vg_lerpf( gui.factive, gui.helper_count?1.0f:0.0f,
- vg.time_frame_delta*2.0f );
+ if( _cutscene.state >= k_cutscene_state_ready )
+ return;
+
+ gui.factive = vg_lerpf( gui.factive, gui.helper_count?1.0f:0.0f, vg.time_frame_delta*2.0f );
ctx->font = &vgf_default_title;
ui_px height = ctx->font->ch + 16;
opacity = 0.1f;
}
- struct ui_vert *bg = ui_fill( ctx, box,
- ui_opacity( GUI_COL_DARK, opacity ) );
-
+ struct ui_vert *bg = ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, opacity ) );
u32 w;
box[0] += 16;
w = ui_text( ctx, box, buf, 1, k_ui_align_middle_left, fg );
ui_flush( ctx, k_ui_shader_colour, NULL );
vg_ui.frosting = 0.0f;
-
f64 loc_t = (vg.time_real - gui.location_time) / 5.0;
if( (loc_t < 1.0) && (gui.location_time != 0.0) )
{
mdl_open( mdl, "models/rs_icons.mdl", alloc );
mdl_load_metadata_block( mdl, alloc );
- gui.icon_submeshes[ k_gui_icon_tick ] = mdl_get_submesh_index( mdl, "icon_tick" );
- gui.icon_submeshes[ k_gui_icon_tick_2d ] = mdl_get_submesh_index( mdl, "icon_tick2d" );
+ gui.icon_submeshes[ k_gui_icon_tick1 ] = mdl_get_submesh_index( mdl, "icon_tick1" );
+ gui.icon_submeshes[ k_gui_icon_tick2 ] = mdl_get_submesh_index( mdl, "icon_tick2" );
+ gui.icon_submeshes[ k_gui_icon_run ] = mdl_get_submesh_index( mdl, "icon_run" );
+ gui.icon_submeshes[ k_gui_icon_challenge ] = mdl_get_submesh_index( mdl, "icon_challenge" );
gui.icon_submeshes[ k_gui_icon_exclaim ] = mdl_get_submesh_index( mdl, "icon_exclaim" );
- gui.icon_submeshes[ k_gui_icon_exclaim_2d ] = mdl_get_submesh_index( mdl, "icon_exclaim2d" );
gui.icon_submeshes[ k_gui_icon_board ] = mdl_get_submesh_index( mdl, "icon_board" );
gui.icon_submeshes[ k_gui_icon_world ] = mdl_get_submesh_index( mdl, "icon_world" );
gui.icon_submeshes[ k_gui_icon_rift ] = mdl_get_submesh_index( mdl, "icon_rift" );
ui_rect end = { panel[0], panel[1] + panel[3] - 48, panel[2], 48 }, a,b;
ui_split_ratio( end, k_ui_axis_v, 0.5f, 2, a, b );
- if( menu_button( ctx, a, R == 0, steam_ready, "Skip" ) )
+ if( menu_button( ctx, a, R == 0, 1, "Skip" ) )
{
_cutscene.fadeout = 1;
_cutscene.fadeout_start = _cutscene.time;
--- /dev/null
+#include "npc_gino.h"
+
+struct
+{
+ enum gino_state
+ {
+ k_gino_none,
+ k_gino_intro,
+ k_gino_normal,
+ }
+ state;
+
+ mdl_context mdl;
+ i32 sm_main, sm_hat;
+
+ f64 command_t;
+ v3f co, p0, p1;
+
+ i32 uid;
+
+ enum gino_sub_state
+ {
+ k_gino_sub_off,
+ k_gino_sub_reading,
+ k_gino_sub_read
+ }
+ sub_state;
+
+ const cs_subtitle *subtitles;
+ i32 sub_index;
+
+ f32 spark_t;
+}
+_gino;
+
+void _npc_gino_speech( const cs_subtitle *subs )
+{
+ _gino.subtitles = subs;
+}
+
+void _npc_gino_goto( v3f pos, i32 uid )
+{
+ if( _gino.uid == uid )
+ return;
+
+ _gino.uid = uid;
+ _gino.state = k_gino_intro;
+ v3_copy( pos, _gino.p1 );
+
+ if( _gino.state == k_gino_none )
+ v3_add( pos, (v3f){0,30,0}, _gino.p0 );
+ else
+ v3_copy( _gino.co, _gino.p0 );
+
+ _gino.command_t = vg.time;
+}
+
+void _npc_gino_init(void)
+{
+ void *alloc = vg_mem.rtmemory;
+ mdl_context *mdl = &_gino.mdl;
+ mdl_open( mdl, "models/gino.mdl", alloc );
+ mdl_load_metadata_block( mdl, alloc );
+ mdl_async_full_load_std( mdl, NULL );
+ _gino.sm_main = mdl_get_submesh_index( mdl, "gino" );
+ _gino.sm_hat = mdl_get_submesh_index( mdl, "gino.hat" );
+ mdl_close( mdl );
+}
+
+void _npc_gino_preupdate(void)
+{
+ if( _gino.state == k_gino_none )
+ return;
+
+ f32 dist2 = v3_dist2( _gino.p1, localplayer.rb.co );
+ if( _world.event == k_world_event_gino )
+ {
+ if( dist2 > 4.0f*4.0f )
+ {
+ if( world_clear_event( k_world_event_gino ) )
+ {
+ _gino.sub_state = k_gino_sub_off;
+ _cutscene.subtitle = NULL;
+ gui_helper_reset( k_gui_helper_mode_clear );
+ }
+ }
+ else
+ {
+ if( (_gino.sub_state != k_gino_sub_read) && button_down( k_srbind_maccept ) )
+ {
+ srinput.state = k_input_state_resume;
+ if( _gino.sub_state == k_gino_sub_reading )
+ _gino.sub_index ++;
+
+ const cs_subtitle *sub = &_gino.subtitles[ _gino.sub_index ];
+
+ if( sub->key )
+ {
+ _gino.sub_state = k_gino_sub_reading;
+ _cutscene.subtitle = sub->value;
+
+ gui_helper_reset( k_gui_helper_mode_black_bars );
+ vg_str text;
+ if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
+ vg_strcat( &text, "Next" );
+ }
+ else
+ {
+ _gino.sub_index = 0;
+ _gino.sub_state = k_gino_sub_read;
+ _cutscene.subtitle = NULL;
+ gui_helper_reset( k_gui_helper_mode_clear );
+ }
+ }
+ }
+ }
+
+ v3f co;
+
+ if( _gino.state == k_gino_normal )
+ {
+ v3_copy( _gino.p1, co );
+
+ if( _world.event == k_world_event_none )
+ {
+ if( dist2 < 3.0f*3.0f )
+ {
+ if( localplayer.subsystem == k_player_subsystem_walk )
+ {
+ if( world_set_event( k_world_event_gino ) )
+ {
+ gui_helper_reset( k_gui_helper_mode_black_bars );
+ vg_str text;
+ if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
+ vg_strcat( &text, "Talk to Gino" );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ f32 t = (vg.time - _gino.command_t) / 2.0;
+ bool end = 0;
+
+ if( t >= 1.0f )
+ {
+ end = 1;
+ t = 1.0f;
+ }
+
+ if( end )
+ _gino.state = k_gino_normal;
+
+ f32 ts = vg_smoothstepf( t );
+ v3_lerp( _gino.p0, _gino.p1, ts, co );
+ co[1] += vg_smoothstepf(1.0f-(fabsf(t-0.5f)*2.0f)) * 8.0f;
+ }
+
+ co[0] += cos( vg.time * 1.23 + 0.3 ) * 0.07f;
+ co[1] += sin( vg.time ) * 0.1f;
+ co[2] += cos( vg.time * 1.1 + 0.3 ) * 0.04f;
+ v3_copy( co, _gino.co );
+
+ if( dist2 < 40.0f*40.0f )
+ {
+ if( _gino.spark_t < 0.0f )
+ {
+ _gino.spark_t += 0.05f+vg_randf64(&vg.rand)*0.1f;
+
+ v3f pos;
+ v3_add( co, (v3f){0,0.16f,0}, pos );
+ f32 a = vg_randf64(&vg.rand) * VG_TAUf,
+ r = 0.43f;
+ pos[0] += sinf( a ) * r;
+ pos[2] += cosf( a ) * r;
+ particle_spawn_cone( &particles_grind, pos, (v3f){0,-1,0}, VG_PIf/2.0f, 2, 4.0f, 0xffEC705A );
+ }
+ else
+ _gino.spark_t -= vg.time_delta;
+ }
+}
+
+void _npc_gino_render( vg_camera *cam )
+{
+ if( _gino.state == k_gino_none )
+ return;
+
+ mesh_bind( &_gino.mdl.mesh );
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, _gino.mdl.textures[0].glname );
+
+ world_instance *world = &_world.main;
+ shader_model_entity_use();
+ shader_model_entity_uTexMain( 0 );
+ shader_model_entity_uCamera( cam->transform[3] );
+ shader_model_entity_uPv( cam->mtx.pv );
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity );
+
+ m4x3f mmdl;
+ v3f v0 = { localplayer.rb.co[0] - _gino.co[0], 0.0f, localplayer.rb.co[2] - _gino.co[2] };
+ v3_normalize( v0 );
+ v3_copy( v0, mmdl[0] );
+ v3_copy( (v3f){0,1,0}, mmdl[1] );
+ v3_cross( mmdl[0], mmdl[1], mmdl[2] );
+ v3_copy( _gino.co, mmdl[3] );
+
+ m4x4f m4mmdl;
+ m4x3_expand( mmdl, m4mmdl );
+ m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl );
+ shader_model_entity_uMdl( mmdl );
+ shader_model_entity_uPvmPrev( m4mmdl );
+ mdl_draw_submesh( &_gino.mdl.submeshes[ _gino.sm_main ] );
+
+ m3x3f mspin;
+ v4f qspin;
+ q_axis_angle( qspin, (v3f){0,1,0}, vg_fractf(vg.time)*VG_TAUf*16.0f );
+ q_m3x3( qspin, mspin );
+ m3x3_mul( mspin, mmdl, mmdl );
+ m4x3_expand( mmdl, m4mmdl );
+ m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl );
+ shader_model_entity_uMdl( mmdl );
+ shader_model_entity_uPvmPrev( m4mmdl );
+ mdl_draw_submesh( &_gino.mdl.submeshes[ _gino.sm_hat ] );
+}
+
+void _npc_gino_imgui( ui_context *ctx )
+{
+ vg_camera *cam = &g_render.cam;
+}
--- /dev/null
+#pragma once
+
+void _npc_gino_init(void);
+void _npc_gino_render( vg_camera *cam );
+void _npc_gino_goto( v3f pos, i32 uid );
+void _npc_gino_preupdate(void);
+void _npc_gino_imgui( ui_context *ctx );
+void _npc_gino_speech( const cs_subtitle *subs );
return 1;
}
+
+static void _skaterift_script_gino_send( ent_script_event *event, i32 which )
+{
+ i32 count = 0;
+ for( u32 i=0; i<event->entity_list->entity_ref_count; i ++ )
+ {
+ u32 ref_index = event->entity_list->entity_ref_start + i;
+ file_entity_ref *ref = af_arritm( &event->world->file_entity_ref, ref_index );
+ u32 type = mdl_entity_id_type( ref->entity_id ),
+ index = mdl_entity_id_id( ref->entity_id );
+
+ if( type == k_ent_marker )
+ {
+ if( count == which )
+ {
+ ent_marker *marker = af_arritm( &event->world->ent_marker, index );
+ _npc_gino_goto( marker->transform.co, which+1 );
+ break;
+ }
+
+ count ++;
+ }
+ }
+}
+
+static bool _skaterift_script_gino_intro( ent_script_event *event )
+{
+ static const cs_subtitle EN0[] =
+ {
+ { "a1", KCOL_JESUS "Hello, I'm Gino!" },
+ { "a2", KCOL_JESUS "Do you remember who you are?" },
+ { "a3", KCOL_JESUS "Pick here." },
+ { NULL, NULL },
+ },
+ EN1[] =
+ {
+ { "a1", KCOL_JESUS "Welcome to almost Heaven.." },
+ { "a2", KCOL_JESUS "For some reason the entrance is blocked" },
+ { "a3", KCOL_JESUS "You'll have to go back home for now" },
+ { "a4", KCOL_JESUS "There are people waiting for you after all." },
+ { NULL, NULL },
+ },
+ EN2[] =
+ {
+ { "a1", KCOL_JESUS "Might want to pick up one of these" },
+ { "a2", KCOL_JESUS "See you at the center Island." },
+ { NULL, NULL },
+ };
+
+ if( event->type == k_escript_event_world_start )
+ {
+ _npc_gino_speech( EN0 );
+ _skaterift_script_gino_send( event, 0 );
+ return 1;
+ }
+
+ if( on_function_trigger( event, 0 ) )
+ {
+ _npc_gino_speech( EN0 );
+ _skaterift_script_gino_send( event, 0 );
+ }
+
+ if( on_function_trigger( event, 1 ) )
+ {
+ _npc_gino_speech( EN1 );
+ _skaterift_script_gino_send( event, 1 );
+ }
+
+ if( on_function_trigger( event, 2 ) )
+ {
+ _npc_gino_speech( EN2 );
+ _skaterift_script_gino_send( event, 2 );
+ }
+
+ return 1;
+}
#include "replay2.h"
#include "user_profile.h"
#include "ent_route.h"
+#include "npc_gino.h"
struct skaterift_globals skaterift =
{
vg_loader_step( ent_tornado_init, NULL );
vg_loader_step( skaterift_load_player_content, NULL );
vg_loader_step( _replay2_init, NULL );
+ vg_loader_step( _npc_gino_init, NULL );
vg_loader_set_user_information( "Compiling shaders" );
vg_bake_shaders();
#include "compass.c"
#include "replay2.c"
#include "user_profile.c"
+#include "npc_gino.c"
//TODO
//#include "vg/submodules/hashmap.c/hashmap.c"
{ "board_maker", _skaterift_script_board_maker },
{ "intro", _skaterift_script_intro },
+ { "gino.intro", _skaterift_script_gino_intro },
{ "hub", _skaterift_script_hub },
{ "tutorial_island", _skaterift_script_tutorial_island },
{
ent_script_update( world );
ent_route_preupdate();
+ _npc_gino_preupdate();
world_routes_update_timer_texts( world );
world_routes_update( world );
ent_traffic_update( world, pos );
{
ent_skateshop_gui( ctx );
_ent_challenge_ui( ctx );
+ _npc_gino_imgui( ctx );
}
bool world_set_event( enum world_event event )
k_world_event_route_leaderboard,
k_world_event_interact,
k_world_event_board_maker,
+ k_world_event_gino,
k_world_event_max
}
event;
if( challenge->flags & k_ent_challenge_locked )
continue;
- enum gui_icon icon = k_gui_icon_exclaim_2d;
- if( challenge->status )
- icon = k_gui_icon_tick_2d;
-
u32 challenge_id = mdl_entity_id( k_ent_challenge, i );
- respawn_map_draw_icon( &world_map.final_cam, icon, challenge->transform.co,
- world_map.closest_entity_id == challenge_id? 1.5f: 1.0f );
+ f32 scale = world_map.closest_entity_id == challenge_id? 1.5f: 1.0f;
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_challenge, challenge->transform.co, scale );
+
+ if( challenge->status )
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_tick2, challenge->transform.co, scale );
+ else
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_tick1, challenge->transform.co, scale );
}
for( u32 i=0; i<af_arrcount(&world->ent_marker); i ++ )
gui_icon_setcolour( colour );
u32 route_id = mdl_entity_id( k_ent_route, i );
- respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_rift_run_2d, route->board_transform[3],
- world_map.closest_entity_id == route_id? 1.5f: 1.0f );
+ f32 scale = world_map.closest_entity_id == route_id? 1.5f: 1.0f;
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_run, route->board_transform[3], scale );
+
+ if( route->flags & k_ent_route_flag_achieve_gold )
+ {
+ gui_icon_setcolour( (v4f){1,1,1,1} );
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_tick2, route->board_transform[3], scale );
+ }
+ else if( route->flags & k_ent_route_flag_achieve_silver )
+ {
+ gui_icon_setcolour( (v4f){1,1,1,1} );
+ respawn_map_draw_icon( &world_map.final_cam, k_gui_icon_tick1, route->board_transform[3], scale );
+ }
}
for( u32 i=0; i<af_arrcount(&world->ent_glider); i ++ )
world_render_both_stages( world, &pass );
}
-static void bindpoint_world_cubemapped( world_instance *world,
- struct world_surface *mat )
+static void bindpoint_world_cubemapped( world_instance *world, struct world_surface *mat )
{
struct shader_props_cubemapped *props = mat->info.props.compiled;
world_get_texture( world, props->tex_diffuse ) );
}
-static void render_world_cubemapped( world_instance *world, vg_camera *cam,
- int enabled )
+static void render_world_cubemapped( world_instance *world, vg_camera *cam, int enabled )
{
if( !af_arrcount( &world->ent_cubemap ) )
return;
}
cutscene_render( world, cam );
+ _npc_gino_render( cam );
}
void render_world( world_instance *world, vg_camera *cam,
if( _world.active_trigger_volumes[i] == index )
goto next_volume;
+ /* on enter */
if( _world.active_trigger_volume_count > VG_ARRAY_LEN(_world.active_trigger_volumes) )
continue;