npcs and tutorial stuff
[carveJwlIkooP6JGAAIwe30JlM.git] / ent_npc.c
index 048a1b9b27bd20f6685512fb42b6dc3d7684fa90..774edff45806ae47ea40dfeefe555847fdf7b7ba 100644 (file)
--- a/ent_npc.c
+++ b/ent_npc.c
@@ -1,9 +1,16 @@
 #include "vg/vg_mem.h"
 #include "ent_npc.h"
 #include "shaders/model_character_view.h"
+#include "input.h"
+#include "player.h"
+#include "gui.h"
 
-struct npc npc_gumpa;
+struct npc npc_gumpa, npc_slowmo, npc_volc_flight;
 static struct skeleton_anim *gumpa_idle;
+static struct skeleton_anim *slowmo_momentum, *slowmo_slide, *slowmo_rewind,
+                            *anim_tutorial_cam;
+static float slowmo_opacity = 0.0f;
+static f64 volc_start_preview = 0.0;
 
 void npc_load_model( struct npc *npc, const char *path )
 {
@@ -20,16 +27,20 @@ void npc_load_model( struct npc *npc, const char *path )
    u32 mtx_size = sizeof(m4x3f)*sk->bone_count;
    npc->final_mtx = vg_linear_alloc( vg_mem.rtmemory, mtx_size );
 
-   if( !mdl_arrcount( &meta->textures ) )
-      vg_fatal_error( "No texture in model" );
+   if( mdl_arrcount( &meta->textures ) )
+   {
+      mdl_texture *tex0 = mdl_arritm( &meta->textures, 0 );
+      void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
+      mdl_fread_pack_file( meta, &tex0->file, data );
 
-   mdl_texture *tex0 = mdl_arritm( &meta->textures, 0 );
-   void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
-   mdl_fread_pack_file( meta, &tex0->file, data );
-
-   vg_tex2d_load_qoi_async( data, tex0->file.pack_size,
-                            VG_TEX2D_NEAREST|VG_TEX2D_CLAMP,
-                            &npc->texture );
+      vg_tex2d_load_qoi_async( data, tex0->file.pack_size,
+                               VG_TEX2D_NEAREST|VG_TEX2D_CLAMP,
+                               &npc->texture );
+   }
+   else
+   {
+      npc->texture = vg.tex_missing;
+   }
 
    mdl_async_load_glmesh( meta, &npc->mesh, NULL );
    mdl_close( meta );
@@ -39,16 +50,162 @@ void npc_init(void)
 {
    npc_load_model( &npc_gumpa, "models/gumpa.mdl" );
    gumpa_idle = skeleton_get_anim( &npc_gumpa.skeleton, "gumpa_idle" );
+
+   npc_load_model( &npc_slowmo, "models/slowmos.mdl" );
+   slowmo_momentum = 
+      skeleton_get_anim( &npc_slowmo.skeleton, "slowmo_momentum" );
+   slowmo_slide = skeleton_get_anim( &npc_slowmo.skeleton, "slowmo_slide" );
+   slowmo_rewind = skeleton_get_anim( &npc_slowmo.skeleton, "slowmo_rewind" );
+
+   npc_load_model( &npc_volc_flight, "models/volc_flight.mdl" );
+   anim_tutorial_cam = 
+      skeleton_get_anim( &npc_volc_flight.skeleton, "tutorial" );
 }
 
 static struct npc *npc_resolve( u32 id )
 {
    if( id == 1 ) return &npc_gumpa;
+   else if( id == 2 ) return &npc_slowmo;
+   else if( id == 3 ) return &npc_volc_flight;
    else return NULL;
 }
 
+static void npc_slowmo_call( ent_npc *npc, ent_call *call )
+{
+   if( call->function == 0 )
+   {
+      gui_helper_clear();
+      vg_str text;
+
+      if( npc->context == 2 )
+      {
+         if( gui_new_helper( input_axis_list[k_sraxis_grab], &text ))
+            vg_strcat( &text, "Crouch (store energy)" );
+         if( gui_new_helper( input_joy_list[k_srjoystick_steer], &text ))
+            vg_strcat( &text, "Slide" );
+      }
+      else if( npc->context == 1 )
+      {
+         if( gui_new_helper( input_axis_list[k_sraxis_grab], &text ))
+            vg_strcat( &text, "Crouch (store energy)" );
+      }
+      else if( npc->context == 3 )
+      {
+         if( gui_new_helper( input_button_list[k_srbind_reset], &text ))
+            vg_strcat( &text, "Rewind time" );
+         if( gui_new_helper( input_button_list[k_srbind_replay_resume], &text ))
+            vg_strcat( &text, "Resume" );
+      }
+   }
+   else if( call->function == -1 )
+   {
+      world_entity_clear_focus();
+      gui_helper_clear();
+   }
+}
+
+void ent_npc_call( world_instance *world, ent_call *call )
+{
+   u32 index = mdl_entity_id_id( call->id );
+   ent_npc *npc = mdl_arritm( &world->ent_npc, index );
+
+   if( npc->id == 2 )
+   {
+      npc_slowmo_call( npc, call );
+   }
+   else if( npc->id == 3 )
+   {
+      if( call->function == 0 )
+      {
+         world_entity_set_focus( call->id );
+         gui_helper_clear();
+         vg_str text;
+         if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
+            vg_strcat( &text, "Preview course" );
+      }
+      else if( call->function == -1 )
+      {
+         world_entity_clear_focus();
+         gui_helper_clear();
+      }
+   }
+   else
+   {
+      if( call->function == 0 )
+      {
+         world_entity_set_focus( call->id );
+         gui_helper_clear();
+         vg_str text;
+         if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
+            vg_strcat( &text, "Talk to ???" );
+      }
+      else if( call->function == -1 )
+      {
+         world_entity_clear_focus();
+         gui_helper_clear();
+      }
+      else 
+      {
+         vg_print_backtrace();
+         vg_error( "Unhandled function id: %i\n", call->function );
+      }
+   }
+}
+
+void ent_npc_preupdate( ent_npc *ent, int active )
+{
+   world_instance *world = world_current_instance();
+
+   if( !active )
+   {
+      if( button_down(k_srbind_maccept) )
+      {
+         world_entity_focus_modal();
+         gui_helper_clear();
+         vg_str text;
+         if( gui_new_helper( input_button_list[k_srbind_mback], &text ))
+            vg_strcat( &text, "leave" );
+
+         volc_start_preview = vg.time;
+      }
+
+      return;
+   }
+
+   if( ent->id == 3 )
+   {
+      player_pose pose;
+      struct skeleton *sk = &npc_volc_flight.skeleton;
+
+      f64 t = (vg.time - volc_start_preview) * 0.5;
+      skeleton_sample_anim_clamped( sk, anim_tutorial_cam, t, pose.keyframes );
+      
+      ent_camera *cam = mdl_arritm( &world->ent_camera, 
+                                     mdl_entity_id_id(ent->camera) );
+      v3_copy( pose.keyframes[0].co, cam->transform.co );
+
+      v4f qp;
+      q_axis_angle( qp, (v3f){1,0,0}, VG_TAUf*0.25f );
+      q_mul( pose.keyframes[0].q, qp, cam->transform.q );
+      q_normalize( cam->transform.q );
+
+      v3_add( ent->transform.co, cam->transform.co, cam->transform.co );
+   }
+
+   world_entity_focus_camera( world, ent->camera );
+
+   if( button_down( k_srbind_mback ) )
+   {
+      world_entity_exit_modal();
+      world_entity_clear_focus();
+      gui_helper_clear();
+   }
+}
+
 void npc_update( ent_npc *ent )
 {
+   if( ent->id == 3 ) return;
+
    struct npc *npc_def = npc_resolve( ent->id );
    VG_ASSERT( npc_def );
 
@@ -57,7 +214,25 @@ void npc_update( ent_npc *ent )
    pose.type = k_player_pose_type_ik;
    pose.board.lean = 0.0f;
 
-   skeleton_sample_anim( sk, gumpa_idle, vg.time, pose.keyframes );
+   if( ent->id == 1 )
+   {
+      skeleton_sample_anim( sk, gumpa_idle, vg.time, pose.keyframes );
+   }
+   else if( ent->id == 2 )
+   {
+      struct skeleton_anim *anim = NULL;
+      if( ent->context == 1 ) anim = slowmo_momentum;
+      else if( ent->context == 2 ) anim = slowmo_slide;
+      else if( ent->context == 3 ) anim = slowmo_rewind;
+
+      VG_ASSERT( anim );
+
+      f32 t        = vg.time*0.5f,
+          animtime = fmodf( t*anim->rate, anim->length ),
+          lt       = animtime / (f32)anim->length;
+      skeleton_sample_anim( sk, anim, t, pose.keyframes );
+      slowmo_opacity = vg_clampf(fabsf(lt-0.5f)*9.0f-3.0f,0,1);
+   }
 
    v3_copy( ent->transform.co, pose.root_co );
    v4_copy( ent->transform.q, pose.root_q );
@@ -66,6 +241,8 @@ void npc_update( ent_npc *ent )
 
 void npc_render( ent_npc *ent, world_instance *world, vg_camera *cam )
 {
+   if( ent->id == 3 ) return;
+
    struct npc *npc_def = npc_resolve( ent->id );
    VG_ASSERT( npc_def );
 
@@ -76,7 +253,16 @@ void npc_render( ent_npc *ent, world_instance *world, vg_camera *cam )
    shader_model_character_view_uTexMain( 0 );
    shader_model_character_view_uCamera( cam->transform[3] );
    shader_model_character_view_uPv( cam->mtx.pv );
-   shader_model_character_view_uDepthCompare( 0 );
+
+   if( ent->id == 2 )
+   {
+      shader_model_character_view_uDepthMode( 2 );
+      shader_model_character_view_uDitherCutoff( slowmo_opacity );
+   }
+   else 
+   {
+      shader_model_character_view_uDepthMode( 0 );
+   }
 
    WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_character_view );