Story event props and such
authorhgn <hgodden00@gmail.com>
Mon, 24 Feb 2025 05:32:04 +0000 (05:32 +0000)
committerhgn <hgodden00@gmail.com>
Mon, 24 Feb 2025 05:32:04 +0000 (05:32 +0000)
content_skaterift/maps/dev_heaven/main.mdl
skaterift_blender/sr_main.py
skaterift_blender/sr_mdl.py
src/control_overlay.c
src/ent_challenge.c
src/ent_challenge.h
src/entity.h
src/player_replay.c
src/skaterift_script.c
src/world_entity.c
src/world_render.c

index 99ee2f8c4f984dcde6336927ff331d1d6b2ec0ed..9e76a375240cf1f563d821c8c5ae82168683a2af 100644 (file)
Binary files a/content_skaterift/maps/dev_heaven/main.mdl and b/content_skaterift/maps/dev_heaven/main.mdl differ
index df9fb17e4dcf9210f445f4c44cc2f492f448c193..211a8dc704db0657665241186c9a9f5b493d0dc4 100644 (file)
@@ -1654,9 +1654,9 @@ class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup):#{
    target_event_leave: bpy.props.IntProperty( name="Leave Ev", default=-1 )
 
    @staticmethod
-   def inspect_target( layout, data, propname, evs = ['_event'] ):#{
+   def inspect_target( layout, data, propname, evs = ['_event'], text='' ):#{
       box = layout.box()
-      box.prop( data[0], propname )
+      box.prop( data[0], propname, text=text )
 
       for evname in evs:#{
          row = box.row()
@@ -1880,6 +1880,7 @@ class SR_OBJECT_ENT_WORLD_INFO(bpy.types.PropertyGroup):
 
    water_safe: bpy.props.BoolProperty(name="Water is Safe")
    no_skating: bpy.props.BoolProperty(name="No Skating")
+   no_rewind: bpy.props.BoolProperty(name="No Rewinding")
 
    @staticmethod
    def sr_inspector( layout, data ):
@@ -1896,6 +1897,7 @@ class SR_OBJECT_ENT_WORLD_INFO(bpy.types.PropertyGroup):
 
       layout.prop( data[0], 'water_safe' )
       layout.prop( data[0], 'no_skating' )
+      layout.prop( data[0], 'no_rewind' )
       layout.prop( data[0], 'wind_scale' )
       layout.prop( data[0], 'skybox' )
    #}
@@ -1957,22 +1959,22 @@ class SR_OBJECT_ENT_CHALLENGE(bpy.types.PropertyGroup):#{
 
    first: bpy.props.PointerProperty( \
             type=bpy.types.Object, name="First Objective", \
-            poll=lambda self,obj: sr_filter_ent_type(obj,['ent_objective']))
+            poll=lambda self,obj: sr_filter_ent_type(obj,['ent_objective','ent_prop']))
 
    camera: bpy.props.PointerProperty( \
            type=bpy.types.Object, name="Camera", \
-           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera']))
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera','ent_objective']))
 
 
    @staticmethod
    def sr_inspector( layout, data ):#{
       layout.prop( data[0], 'alias' )
-      layout.prop( data[0], 'camera' )
-      layout.prop( data[0], 'first' )
+      layout.prop( data[0], 'camera', text=("Camera" if not data[0].is_story else "Related Objective") )
+      layout.prop( data[0], 'first', text=("First Objective" if not data[0].is_story else "Indicator Prop") )
       layout.prop( data[0], 'time_limit' )
       layout.prop( data[0], 'is_story' )
-      SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target' )
-      SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'reset' )
+      SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'target', text=("On Activate" if data[0].is_story else "On Complete") )
+      SR_OBJECT_ENT_VOLUME.inspect_target( layout, data, 'reset', text=("On Finish" if data[0].is_story else "On Reset") )
    #}
 #}
 
index fafbd7f4a7c5b4b13d3602376cb1fec304e9f09a..37a7ca1891bedd58b006bd693b62c48358a29237 100644 (file)
@@ -813,6 +813,9 @@ def _mdl_compiler_compile_entities():
             if obj_data.no_skating:
                flags |= 0x4
 
+            if obj_data.no_rewind:
+               flags |= 0x8
+
             worldinfo.flags = flags
             worldinfo.pstr_skybox = _af_pack_string( obj_data.skybox )
             worldinfo.wind_scale = obj_data.wind_scale
index 3d9d6aceb2e04a8161939b92f631e308c4d24565..dcc5b3916f101f63559d2f201dea41bc3dce2da4 100644 (file)
@@ -432,7 +432,7 @@ void control_overlay_render(void)
       if( press_dpad_e )
          render_overlay_mesh( ov_dpad_e );
 
-      colorize( press_dpad_w, !(_world.main.info.flags & k_world_flag_no_skating) );
+      colorize( press_dpad_w, !(_world.main.info.flags & k_world_flag_no_rewind) );
       render_overlay_mesh( ov_text_dw_rewind );
       if( press_dpad_w )
          render_overlay_mesh( ov_dpad_w );
@@ -707,7 +707,7 @@ void control_overlay_render(void)
       shader_model_menu_uColour( cnorm );
       shader_model_menu_uMdl( mmdl );
 
-      colorize( press_r, !(_world.main.info.flags & k_world_flag_no_skating) );
+      colorize( press_r, !(_world.main.info.flags & k_world_flag_no_rewind) );
       draw_key( press_r, 0 );
       render_overlay_mesh( ov_text_rewind );
 
index f4681ed8e3e502d64b0ece0dec8790b7f5ed7111..0d68dfbd1ce0292f2b82b93e4e59ede17d973049 100644 (file)
@@ -16,8 +16,8 @@ entity_call_result ent_challenge_call( world_instance *world, ent_call *call )
          vg_info( "challenge( '%s' )\n", af_str( &world->meta.af, challenge->pstr_alias) );
          ent_call call;
          call.data = NULL;
-         call.function = challenge->target_event;
-         call.id = challenge->target;
+         call.function = challenge->on_complete_event;
+         call.id = challenge->on_complete_id;
          entity_call( world, &call );
       }
       challenge->status = 1;
@@ -34,7 +34,7 @@ entity_call_result ent_challenge_call( world_instance *world, ent_call *call )
             gui_helper_reset( 1 );
             vg_str text;
             if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
-               vg_strcat( &text, "View Challenge" );
+               vg_strcat( &text, (challenge->flags & k_ent_challenge_is_story)? "Play video": "View Challenge" );
          }
       }
 
@@ -57,22 +57,54 @@ entity_call_result ent_challenge_call( world_instance *world, ent_call *call )
       return k_entity_call_result_unhandled;
 }
 
+void ent_challenge_visibility( ent_challenge *challenge, bool visible )
+{
+   world_instance *world = &_world.main;
+   if( challenge->indicator_prop_id )
+   {
+      ent_prop *prop = af_arritm( &world->ent_prop, mdl_entity_id_id( challenge->indicator_prop_id ) );
+
+      if( visible ) prop->flags &= ~((u32)k_prop_flag_hidden);
+      else          prop->flags |= k_prop_flag_hidden;
+   }
+
+   if( challenge->objective_id )
+   {
+      ent_objective *objective = af_arritm( &world->ent_objective, mdl_entity_id_id( challenge->objective_id ) );
+
+      if( visible ) objective->flags &= ~((u32)k_ent_objective_hidden);
+      else          objective->flags |= k_ent_objective_hidden;
+   }
+}
+
 void ent_challenge_update(void)
 {
+   world_instance *world = &_world.main;
+   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_is_story )
+      {
+         if( challenge->indicator_prop_id )
+         {
+            ent_prop *prop = af_arritm( &world->ent_prop, mdl_entity_id_id( challenge->indicator_prop_id ) );
+            q_axis_angle( prop->transform.q, (v3f){0,1,0}, vg.time );
+         }
+      }
+   }
+
    if( _world.event != k_world_event_challenge )
       return;
 
-   world_instance *world = &_world.main;
-
    u32 index = mdl_entity_id_id( _world.active_challenge_id );
    ent_challenge *challenge = af_arritm( &world->ent_challenge, index );
 
    if( _world.challenge_state == k_challenge_state_viewing )
    {
-      if( challenge->camera )
+      if( challenge->camera_id )
       {
          vg_camera temp;
-         ent_camera_unpack( af_arritm( &world->ent_camera, mdl_entity_id_id(challenge->camera) ), &temp );
+         ent_camera_unpack( af_arritm( &world->ent_camera, mdl_entity_id_id(challenge->camera_id) ), &temp );
          world_set_entity_driven_camera( &temp );
       }
 
@@ -84,11 +116,11 @@ void ent_challenge_update(void)
          menu.disable_open = 0;
          srinput.state = k_input_state_resume;
 
-         u32 first_objective_index = mdl_entity_id_id( challenge->first );
+         u32 first_objective_index = mdl_entity_id_id( challenge->first_objective_id );
          _world.challenge_target = af_arritm( &world->ent_objective, first_objective_index );
          _world.challenge_timer = 0.0f;
 
-         u32 next = challenge->first;
+         u32 next = challenge->first_objective_id;
          while( mdl_entity_id_type(next) == k_ent_objective )
          {
             u32 index = mdl_entity_id_id( next );
@@ -114,9 +146,9 @@ void ent_challenge_update(void)
    {
       f32 min_dist2 = 999999.9f;
 
-      if( mdl_entity_id_type( challenge->first ) == k_ent_objective )
+      if( mdl_entity_id_type( challenge->first_objective_id ) == k_ent_objective )
       {
-         u32 next = challenge->first;
+         u32 next = challenge->first_objective_id;
          while( mdl_entity_id_type(next) == k_ent_objective )
          {
             u32 index = mdl_entity_id_id( next );
@@ -153,8 +185,8 @@ void ent_challenge_update(void)
             gui_helper_reset( k_gui_helper_mode_clear );
             ent_call call;
             call.data = NULL;
-            call.function = challenge->target_event;
-            call.id = challenge->target;
+            call.function = challenge->on_activate_event;
+            call.id = challenge->on_activate_id;
             entity_call( &_world.main, &call );
          }
       }
index 73641bd4d3f4f98ac45ec528384c38923abd8931..00146706693b7c98000fe007525283cc667cbf8d 100644 (file)
@@ -2,3 +2,4 @@
 #include "entity.h"
 
 entity_call_result ent_challenge_call( world_instance *world, ent_call *call );
+void ent_challenge_visibility( ent_challenge *challenge, bool visible );
index 83bb0508fdc2e47943121b4a921ff114ef0c0224..4d011c7dee34267ae1c1082bbdec77635e5e5fb7 100644 (file)
@@ -488,7 +488,8 @@ enum world_flag
 {
    k_world_flag_fixed_time = 0x1,
    k_world_flag_water_is_safe = 0x2,
-   k_world_flag_no_skating = 0x4
+   k_world_flag_no_skating = 0x4,
+   k_world_flag_no_rewind = 0x8
 };
 
 struct ent_worldinfo
@@ -589,14 +590,35 @@ enum ent_challenge_flag
 struct ent_challenge{
    mdl_transform transform;
    u32 pstr_alias,
-       flags,
-       target;
-   i32 target_event;
+       flags;
+
+   union
+   {
+      u32 on_complete_id,
+          on_activate_id;
+   };
+   union
+   {
+      i32 on_complete_event,
+          on_activate_event;
+   };
+
    u32 reset;
    i32 reset_event;
-   u32 first,
-       camera,
-       status;
+
+   union
+   {
+      u32 first_objective_id,
+          indicator_prop_id;
+   };
+       
+   union
+   {
+      u32 camera_id,
+          objective_id;
+   };
+
+   u32 status;
 };
 
 struct ent_relay {
@@ -617,6 +639,11 @@ struct ent_miniworld {
    u32 proxy;
 };
 
+enum prop_flag
+{
+   k_prop_flag_hidden = 0x1
+};
+
 struct ent_prop {
    mdl_transform transform;
    u32 submesh_start, submesh_count, flags, pstr_alias;
index 3c7060fd799fd8bc1d85e3941043ce6efe8362ab..f0ad6d488296be1347ff120a0ac97cdb9ea9b41a 100644 (file)
@@ -762,7 +762,7 @@ void skaterift_replay_post_render(void)
    /* capture the current resume frame at the very last point */
    if( button_down( k_srbind_reset ) )
    {
-      if( _world.main.info.flags & k_world_flag_no_skating )
+      if( _world.main.info.flags & k_world_flag_no_rewind )
       {
          gui_location_print_ccmd( 1, (const char *[]){ KRED "Rewind is not allowed here.." } );
       }
index 23a0347dc27ddb6fce3a8a5943811bc14482f763..682e423f0b9fa186ede449c1ededef1aea6dae7e 100644 (file)
@@ -1871,8 +1871,7 @@ enum script_action
    k_script_action_play
 };
 
-static void _skaterift_script_hook_apply_action( u32 script_id,
-                                                 enum script_action action )
+static void _skaterift_script_hook_apply_action( u32 script_id, enum script_action action )
 {
    struct script_info *info = &_script_infos[ script_id ];
 
@@ -1881,7 +1880,10 @@ static void _skaterift_script_hook_apply_action( u32 script_id,
       info->availible = 1;
 
       if( info->linked_challenge )
+      {
          info->linked_challenge->flags &= ~((u32)k_ent_challenge_locked);
+         ent_challenge_visibility( info->linked_challenge, 1 );
+      }
    }
 
    if( action == k_script_action_reset )
@@ -1890,7 +1892,10 @@ static void _skaterift_script_hook_apply_action( u32 script_id,
       info->viewed_time = 0;
 
       if( info->linked_challenge )
+      {
          info->linked_challenge->flags |= (u32)k_ent_challenge_locked;
+         ent_challenge_visibility( info->linked_challenge, 0 );
+      }
    }
 
    if( action == k_script_action_play )
@@ -1900,6 +1905,9 @@ static void _skaterift_script_hook_apply_action( u32 script_id,
          _script.script_id = k_escript_script_id_max;
 
       info->viewed_time = 9999; /* TODO */
+
+      if( info->linked_challenge )
+         ent_challenge_visibility( info->linked_challenge, 0 );
    }
 
    if( action == k_script_action_info )
index e550518540c74843f3bec309ecb980d1330fe194..e992ae3c90397603f889b06fba401ab30ad0030a 100644 (file)
@@ -830,14 +830,25 @@ void world_entity_start( world_instance *world, vg_msg *sav )
          {
             script->linked_challenge = challenge;
 
+            bool hide_linked = 0;
+
             if( !script->availible )
             {
+               hide_linked = 1;
                challenge->flags |= k_ent_challenge_locked;
             }
+
+            if( script->viewed_time )
+               hide_linked = 1;
+
+            if( hide_linked )
+               ent_challenge_visibility( challenge, 0 );
          }
       }
       else
       {
+         world->events[i].story_script = NULL;
+
          u32 result;
          vg_msg_getkvintg( sav, alias, k_vg_msg_u32, &result, NULL );
 
index 6db609582444c3ed3aec2d0b1c5442a40ecd637a..98b27e97179cee1bd5f116c3d3952a30ae4e3c26 100644 (file)
@@ -200,7 +200,7 @@ static void world_render_props( world_instance *world, u32 material_id, struct w
    for( u32 j=0; j<af_arrcount( &world->ent_prop ); j++ )
    {
       ent_prop *prop = af_arritm( &world->ent_prop, j );
-      if( prop->flags & k_world_flag_fixed_time ) 
+      if( prop->flags & k_prop_flag_hidden )
          continue;
 
       world_render_submeshes( world, pass, &prop->transform, prop->submesh_start, prop->submesh_count, material_id );
@@ -514,7 +514,7 @@ static void world_render_challenges( world_instance *world, struct world_pass *p
       shader_scene_fxglow_uUvOffset( (v2f){ 8.0f/256.0f, 0.0f } );
       challenge_list[ challenge_count ++ ] = challenge_index;
 
-      u32 next = challenge->first;
+      u32 next = challenge->first_objective_id;
       while( mdl_entity_id_type(next) == k_ent_objective )
       {
          u32 index = mdl_entity_id_id( next );
@@ -607,12 +607,16 @@ static void world_render_challenges( world_instance *world, struct world_pass *p
    /* render texts */
    font3d_bind( &gui.font, k_font_shader_world, 0, world, &g_render.cam );
 
-   u32 count = 0;
+   u32 count = 0, total = 0;
    for( u32 i=0; i<af_arrcount(&world->ent_challenge); i++ )
    {
       ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
-      if( challenge->status ) 
-         count ++;
+      if( !(challenge->flags & k_ent_challenge_is_story) )
+      {
+         if( challenge->status ) 
+            count ++;
+         total ++;
+      }
    }
 
    char buf[32];
@@ -620,7 +624,7 @@ static void world_render_challenges( world_instance *world, struct world_pass *p
    vg_strnull( &str, buf, sizeof(buf) );
    vg_strcati32( &str, count );
    vg_strcatch( &str, '/' );
-   vg_strcati32( &str, af_arrcount(&world->ent_challenge) );
+   vg_strcati32( &str, total );
 
    f32 w = font3d_string_width( 1, buf );
    m4x3f mlocal;
@@ -632,8 +636,11 @@ static void world_render_challenges( world_instance *world, struct world_pass *p
    for( u32 i=0; i<challenge_count; i++ )
    {
       u32 index = challenge_list[ i ];
-
       ent_challenge *challenge = af_arritm( &world->ent_challenge, index );
+
+      if( challenge->flags & k_ent_challenge_is_story )
+         continue;
+
       m4x3f mmdl;
       mdl_transform_m4x3( &challenge->transform, mmdl );
       m4x3_mul( mmdl, mlocal, mmdl );