From: hgn Date: Sun, 21 Jan 2024 14:10:15 +0000 (+0000) Subject: sandsurf/glide basics X-Git-Url: https://skaterift.com/git/?a=commitdiff_plain;h=4c3dc94e7221f599491e7d111cac3d51d8d83b17;p=carveJwlIkooP6JGAAIwe30JlM.git sandsurf/glide basics --- diff --git a/blender_export.py b/blender_export.py index f64989b..695fff0 100644 --- a/blender_export.py +++ b/blender_export.py @@ -3674,7 +3674,9 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup): ('1','wood',''), ('2','grass',''), ('3','tiles',''), - ('4','metal','') + ('4','metal',''), + ('5','snow (low friction)',''), + ('6','sand (medium friction)','') ]) collision: bpy.props.BoolProperty( \ diff --git a/ent_tornado.c b/ent_tornado.c new file mode 100644 index 0000000..d59c6b7 --- /dev/null +++ b/ent_tornado.c @@ -0,0 +1,83 @@ +#include "world.h" +#include "particle.h" + +static f32 k_tornado_strength = 0.0f, + k_tornado_ratio = 0.5f, + k_tornado_range = 10.f; + +static void ent_tornado_init(void){ + vg_console_reg_var( "k_tonado_strength", &k_tornado_strength, + k_var_dtype_f32, VG_VAR_PERSISTENT|VG_VAR_CHEAT ); + vg_console_reg_var( "k_tonado_ratio", &k_tornado_ratio, + k_var_dtype_f32, VG_VAR_PERSISTENT|VG_VAR_CHEAT ); + vg_console_reg_var( "k_tonado_range", &k_tornado_range, + k_var_dtype_f32, VG_VAR_PERSISTENT|VG_VAR_CHEAT ); +} + +static void ent_tornado_debug(void) { + world_instance *world = world_current_instance(); + for( u32 i=0; ient_marker); i ++ ){ + ent_marker *marker = mdl_arritm( &world->ent_marker, i ); + + if( MDL_CONST_PSTREQ( &world->meta, marker->pstr_alias, "tornado" ) ){ + v3f p1; + v3_add( marker->transform.co, (v3f){0,20,0}, p1 ); + vg_line( marker->transform.co, p1, VG__RED ); + + m4x3f mmdl; + m4x3_identity( mmdl ); + v3_copy( marker->transform.co, mmdl[3] ); + vg_line_sphere( mmdl, k_tornado_range, 0 ); + } + } +} + +static void ent_tornado_forces( v3f co, v3f cv, v3f out_a ){ + world_instance *world = world_current_instance(); + v3_zero( out_a ); + + for( u32 i=0; ient_marker); i ++ ){ + ent_marker *marker = mdl_arritm( &world->ent_marker, i ); + + if( MDL_CONST_PSTREQ( &world->meta, marker->pstr_alias, "tornado" ) ){ + v3f d, dir; + v3_sub( co, marker->transform.co, d ); + d[1] = 0.0f; + + f32 dist = v3_length( d ); + v3_normalize( d ); + + v3_cross( d, (v3f){0,1,0}, dir ); + if( v3_dot( dir, cv ) < 0.0f ) + v3_negate( dir, dir ); + + f32 s = vg_maxf(0.0f, 1.0f-dist/k_tornado_range), + F0 = s*k_tornado_strength, + F1 = s*s*k_tornado_strength; + + v3_muladds( out_a, dir, F0 * k_tornado_ratio, out_a ); + v3_muladds( out_a, d, F1 * -(1.0f-k_tornado_ratio), out_a ); + } + } +} + +static void ent_tornado_pre_update(void){ + world_instance *world = world_current_instance(); + for( u32 i=0; ient_marker); i ++ ){ + ent_marker *marker = mdl_arritm( &world->ent_marker, i ); + + if( MDL_CONST_PSTREQ( &world->meta, marker->pstr_alias, "tornado" ) ){ + v3f co; + vg_rand_sphere( &vg.rand, co ); + + v3f tangent = { co[2], 0, co[0] }; + + f32 s = vg_signf( co[1] ); + v3_muls( tangent, s*10.0f, tangent ); + co[1] *= s; + + v3_muladds( marker->transform.co, co, k_tornado_range, co ); + particle_spawn( &particles_env, co, tangent, 2.0f, 0xffffffff ); + } + } +} diff --git a/maps_src/dev_flatworld/main.mdl b/maps_src/dev_flatworld/main.mdl index 7860b3f..10619c5 100644 Binary files a/maps_src/dev_flatworld/main.mdl and b/maps_src/dev_flatworld/main.mdl differ diff --git a/model.h b/model.h index a182e51..62438dc 100644 --- a/model.h +++ b/model.h @@ -26,11 +26,13 @@ enum mdl_shader{ }; enum mdl_surface_prop{ - k_surface_prop_concrete = 0, - k_surface_prop_wood = 1, - k_surface_prop_grass = 2, - k_surface_prop_tiles = 3, - k_surface_prop_metal = 4 + k_surface_prop_concrete = 0, + k_surface_prop_wood = 1, + k_surface_prop_grass = 2, + k_surface_prop_tiles = 3, + k_surface_prop_metal = 4, + k_surface_prop_snow = 5, + k_surface_prop_sand = 6 }; enum material_flag{ diff --git a/particle.h b/particle.h index 14b2e66..fb4d27f 100644 --- a/particle.h +++ b/particle.h @@ -33,6 +33,11 @@ static particles_grind = { .scale = 0.02f, .velocity_scale = 0.001f, .width = 0.0125f +}, +particles_env = { + .scale = 0.04f, + .velocity_scale = 0.001f, + .width = 0.25f }; static void particle_alloc( particle_system *sys, u32 max ); diff --git a/player.c b/player.c index 7a099f0..3a5c100 100644 --- a/player.c +++ b/player.c @@ -377,6 +377,7 @@ static void player__networked_sfx( u8 system, u8 priority, u8 id, #include "player_skate.c" #include "player_dead.c" #include "player_drive.c" +#include "player_glide.c" #include "player_basic_info.c" #include "player_render.c" diff --git a/player.h b/player.h index f837cb9..41d5274 100644 --- a/player.h +++ b/player.h @@ -12,6 +12,7 @@ enum player_subsystem{ k_player_subsystem_dead = 2, k_player_subsystem_drive = 3, k_player_subsystem_basic_info = 4, + k_player_subsystem_glide = 5, k_player_subsystem_max, k_player_subsystem_invalid = 255 }; @@ -68,6 +69,7 @@ struct player_subsystem_interface{ #include "player_skate.h" #include "player_dead.h" #include "player_drive.h" +#include "player_glide.h" #include "player_basic_info.h" #include "player_replay.h" @@ -192,7 +194,8 @@ struct player_subsystem_interface static *player_subsystems[] = { [k_player_subsystem_dead] = &player_subsystem_dead, [k_player_subsystem_drive] = &player_subsystem_drive, [k_player_subsystem_skate] = &player_subsystem_skate, - [k_player_subsystem_basic_info]=&player_subsystem_basic_info + [k_player_subsystem_basic_info]=&player_subsystem_basic_info, + [k_player_subsystem_glide] = &player_subsystem_glide, }; /* diff --git a/player_effects.c b/player_effects.c index 2bfc3bf..9b13445 100644 --- a/player_effects.c +++ b/player_effects.c @@ -17,7 +17,7 @@ static void effect_spark_apply( effect_spark *ef, v3f co, v3f v, f32 dt ){ if( !ef->colour ) return; if( ef->t < 0.0f ){ - ef->t = 0.05f+vg_randf64(&vg.rand)*0.1f; + ef->t += 0.05f+vg_randf64(&vg.rand)*0.1f; v3f dir; v3_copy( v, dir ); diff --git a/player_effects.h b/player_effects.h index ae0f95e..c52361d 100644 --- a/player_effects.h +++ b/player_effects.h @@ -20,7 +20,7 @@ static void effect_spark_apply( effect_spark *ef, v3f co, v3f v, f32 dt ); struct player_effects_data { effect_blink blink; - effect_spark spark; + effect_spark spark, sand; }; #endif /* PLAYER_EFFECTS */ diff --git a/player_glide.c b/player_glide.c new file mode 100644 index 0000000..80cb2bb --- /dev/null +++ b/player_glide.c @@ -0,0 +1,186 @@ +#ifndef PLAYER_GLIDE_C +#define PLAYER_GLIDE_C + +#include "player_glide.h" +#include "input.h" + +static f32 k_glide_steer = 2.0f, + k_glide_cl = 0.04f, + k_glide_cs = 0.02f, + k_glide_drag = 0.0001f, + k_glide_slip_yaw = 0.1f, + k_glide_lift_pitch = 0.0f, + k_glide_wing_orient = -0.1f, + k_glide_balance = 1.0f; + +static i32 k_glide_pause = 0; + +static void player_glide_pre_update(void){ +} + +static void massless_accel( rigidbody *rb, v3f delta, v3f impulse ){ + /* linear */ + v3_muladds( rb->v, impulse, k_rb_delta, rb->v ); + + /* Angular velocity */ + v3f wa; + v3_cross( delta, impulse, wa ); + v3_muladds( rb->w, wa, k_rb_delta, rb->w ); +} + +static void calculate_lift( v3f vl, f32 aoa_bias, + v3f axis, v3f back, f32 power, + v3f out_force ){ + v3f up; + v3_cross( back, axis, up ); + + v3f wind; + v3_muladds( vl, axis, -v3_dot(axis,vl), wind ); + + f32 windv2 = v3_length2(wind), + aoa = atan2f( v3_dot( up, wind ), v3_dot( back, wind ) ) + aoa_bias, + cl = aoa / VG_PIf, /* TODO: make it a curve */ + L = windv2 * cl * power; + + v3f lift_dir; + v3_normalize( wind ); + v3_cross( wind, axis, lift_dir ); + + /* this is where induced drag (from the flappy things) would go */ + + v3_muls( lift_dir, L, out_force ); +} + +static void calculate_drag( v3f vl, f32 cd, v3f out_force ){ + f32 v2 = v3_length2( vl ); + v3f dir; + v3_copy( vl, dir ); + v3_normalize( dir ); + v3_muls( vl, -cd*v2, out_force ); +} + +static void player_glide_update(void){ + rigidbody *rb = &localplayer.rb; + vg_line_sphere( rb->to_world, 1.0f, 0 ); + + v2f steer; + joystick_state( k_srjoystick_steer, steer ); + + /* lift */ + v3f vl, wl; + m3x3_mulv( rb->to_local, rb->v, vl ); + m3x3_mulv( rb->to_local, rb->w, wl ); + + v3f F, Flift, Fslip, Fdrag, FslipW, FliftW; + + calculate_lift( vl, steer[1]*k_glide_steer, + (v3f){1,0,0}, + (v3f){0,sinf(k_glide_wing_orient),cosf(k_glide_wing_orient)}, + k_glide_cl, Flift ); + v3_copy( Flift, player_glide.info_lift ); + v3_cross( (v3f){0,0,0}, Flift, FliftW ); + + calculate_lift( vl, 0.0f, + (v3f){0,1,0},(v3f){0,0,1}, + k_glide_cs, Fslip ); + v3_copy( Fslip, player_glide.info_slip ); + v3_cross( (v3f){0,k_glide_lift_pitch,k_glide_slip_yaw}, Fslip, FslipW ); + + calculate_drag( vl, k_glide_drag, Fdrag ); + v3_copy( Fdrag, player_glide.info_drag ); + + v3f balance = {0.0f,-k_glide_balance,0.0f}; + m3x3_mulv( rb->to_local, balance, balance ); + vg_info( PRINTF_v3f( balance ) ); + + v3f Fw = { + steer[1]*k_glide_steer - balance[2], + 0.0f, + -steer[0]*k_glide_steer + balance[0], + }; + + if( player_glide.ticker ){ + player_glide.ticker --; + return; + } + player_glide.ticker += k_glide_pause; + + /* apply forces */ + v3_add( Flift, Fslip, F ); + v3_add( F, Fdrag, F ); + + m3x3_mulv( rb->to_world, F, F ); + v3_muladds( rb->v, F, k_rb_delta, rb->v ); + + v3_add( Fw, FslipW, Fw ); + v3_add( Fw, FliftW, Fw ); + m3x3_mulv( rb->to_world, Fw, Fw ); + v3_muladds( rb->w, Fw, k_rb_delta, rb->w ); + + rb_iter( rb ); + rb_update_transform( rb ); +} + +static void player_glide_post_update(void){ +} + +static void player_glide_animate(void){ + struct player_glide *g = &player_glide; + struct player_glide_animator *animator = &g->animator; + rb_extrapolate( &localplayer.rb, animator->root_co, animator->root_q ); +} + +static void player_glide_pose( void *_animator, player_pose *pose ){ + struct skeleton *sk = &localplayer.skeleton; + struct player_glide_animator *animator = _animator; + + skeleton_sample_anim( sk, player_glide.anim_temp, 0.0f, pose->keyframes ); + + v3_copy( animator->root_co, pose->root_co ); + v4_copy( animator->root_q, pose->root_q ); +} + +static void player_glide_post_animate(void){ + if( localplayer.cam_control.camera_mode == k_cam_firstperson ) + localplayer.cam_velocity_influence = 0.0f; + else + localplayer.cam_velocity_influence = 0.0f; + + v3f fwd; + v3_muls( localplayer.rb.to_world[2], -1.0f, fwd ); + v3_angles( fwd, localplayer.angles ); +} + +static void player_glide_im_gui(void){ + player__debugtext( 1, "Nothing here" ); + player__debugtext( 1, " lift: %.2f %.2f %.2f", + player_glide.info_lift[0], + player_glide.info_lift[1], + player_glide.info_lift[2] ); + player__debugtext( 1, " slip: %.2f %.2f %.2f", + player_glide.info_slip[0], + player_glide.info_slip[1], + player_glide.info_slip[2] ); + player__debugtext( 1, " drag: %.2f %.2f %.2f", + player_glide.info_drag[0], + player_glide.info_drag[1], + player_glide.info_drag[2] ); +} + +static void player_glide_bind(void){ + struct skeleton *sk = &localplayer.skeleton; + player_glide.anim_temp = skeleton_get_anim( sk, "idle_cycle+y" ); + + u32 mask = VG_VAR_CHEAT|VG_VAR_PERSISTENT; + VG_VAR_F32( k_glide_steer, flags=mask ); + VG_VAR_F32( k_glide_cl, flags=mask ); + VG_VAR_F32( k_glide_cs, flags=mask ); + VG_VAR_F32( k_glide_drag, flags=mask ); + VG_VAR_F32( k_glide_slip_yaw, flags=mask ); + VG_VAR_F32( k_glide_lift_pitch, flags=mask ); + VG_VAR_I32( k_glide_pause, flags=mask ); + VG_VAR_F32( k_glide_balance, flags=mask ); + VG_VAR_F32( k_glide_wing_orient, flags=mask ); +} + +#endif /* PLAYER_GLIDE_C */ diff --git a/player_glide.h b/player_glide.h new file mode 100644 index 0000000..e50fde3 --- /dev/null +++ b/player_glide.h @@ -0,0 +1,48 @@ +#ifndef PLAYER_GLIDE_H +#define PLAYER_GLIDE_H + +#include "player.h" + +struct player_glide { + struct skeleton_anim *anim_temp; + + struct player_glide_animator { + v3f root_co; + v4f root_q; + } + animator; + + v3f info_lift, + info_slip, + info_drag; + + u32 ticker; +} +static player_glide; + +static void player_glide_pre_update(void); +static void player_glide_update(void); +static void player_glide_post_update(void); +static void player_glide_animate(void); +static void player_glide_pose( void *animator, player_pose *pose ); + +static void player_glide_post_animate(void); +static void player_glide_im_gui(void); +static void player_glide_bind(void); + +struct player_subsystem_interface static player_subsystem_glide = { + .pre_update = player_glide_pre_update, + .update = player_glide_update, + .post_update = player_glide_post_update, + .animate = player_glide_animate, + .pose = player_glide_pose, + .post_animate = player_glide_post_animate, + .im_gui = player_glide_im_gui, + .bind = player_glide_bind, + + .animator_data = &player_glide.animator, + .animator_size = sizeof(player_glide.animator), + .name = "Glide" +}; + +#endif /* PLAYER_GLIDE_H */ diff --git a/player_replay.c b/player_replay.c index 6fea7d9..31c4c74 100644 --- a/player_replay.c +++ b/player_replay.c @@ -267,21 +267,18 @@ static void skaterift_record_frame( replay_buffer *replay, u16 gamestate_size = 0; if( save_state ){ + /* TODO: have as part of system struct */ gamestate_size = (u32 []){ [k_player_subsystem_walk ] = sizeof(struct player_walk_state), [k_player_subsystem_drive] = 0, [k_player_subsystem_skate] = sizeof(struct player_skate_state), [k_player_subsystem_dead ] = localplayer.ragdoll.part_count * - sizeof(struct replay_rb) + sizeof(struct replay_rb), + [k_player_subsystem_glide] = 0, }[ localplayer.subsystem ]; } - u16 animator_size = (u16 []){ - [k_player_subsystem_walk ] = sizeof(struct player_walk_animator), - [k_player_subsystem_drive] = 0, - [k_player_subsystem_skate] = sizeof(struct player_skate_animator), - [k_player_subsystem_dead ] = sizeof(struct player_dead_animator) - }[ localplayer.subsystem ]; + u16 animator_size = player_subsystems[localplayer.subsystem]->animator_size; replay_frame *frame = replay_newframe( replay, animator_size, gamestate_size, @@ -347,6 +344,9 @@ static void skaterift_record_frame( replay_buffer *replay, else if( localplayer.subsystem == k_player_subsystem_dead ){ memcpy( dst, &player_dead.animator, animator_size ); } + else if( localplayer.subsystem == k_player_subsystem_glide ){ + memcpy( dst, &player_glide.animator, animator_size ); + } /* sound effects */ memcpy( replay_frame_data( frame, k_replay_framedata_sfx ), diff --git a/player_skate.c b/player_skate.c index 779ba75..6d9aa92 100644 --- a/player_skate.c +++ b/player_skate.c @@ -8,6 +8,8 @@ #include "ent_skateshop.h" #include "addon.h" +#include "ent_tornado.c" + static void player__skate_bind(void){ struct skeleton *sk = &localplayer.skeleton; rb_update_transform( &localplayer.rb ); @@ -403,18 +405,29 @@ static void player__approximate_best_trajectory(void){ inf->gravity = gravity; v3_copy( launch_v, inf->v ); + /* initial conditions */ + v3f v; + v3_copy( launch_v, v ); + v3_copy( launch_co, co1 ); + for( int i=1; i<=50; i++ ){ - float t = (float)i * k_trace_delta; + f32 t = (f32)i * k_trace_delta; - v3_muls( launch_v, t, co1 ); - co1[1] += -0.5f * gravity * t*t; - v3_add( launch_co, co1, co1 ); + /* integrate forces */ + v3f a; + ent_tornado_forces( co1, v, a ); + a[1] -= gravity; - float launch_vy = launch_v[1]; + /* position */ + v3_muladds( co1, v, k_trace_delta, co1 ); + v3_muladds( co1, a, 0.5f*k_trace_delta*k_trace_delta, co1 ); + + /* velocity */ + v3_muladds( v, a, k_trace_delta, v ); int search_for_grind = 1; if( grind_located ) search_for_grind = 0; - if( launch_vy - gravity*t > 0.0f ) search_for_grind = 0; + if( v[1] > 0.0f ) search_for_grind = 0; /* REFACTOR */ @@ -448,13 +461,9 @@ static void player__approximate_best_trajectory(void){ } if( search_for_grind ){ - v3f ve; - v3_copy( launch_v, ve ); - ve[1] += -gravity * t; - - if( skate_grind_scansq( closest, ve, 0.5f, &grind ) ){ + if( skate_grind_scansq( closest, v, 0.5f, &grind ) ){ /* check alignment */ - v2f v0 = { ve[0], ve[2] }, + v2f v0 = { v[0], v[2] }, v1 = { grind.dir[0], grind.dir[2] }; v2_normalize( v0 ); @@ -467,7 +476,7 @@ static void player__approximate_best_trajectory(void){ a_min = cosf( VG_PIf * 0.05f ); /* check speed */ - if( (fabsf(v3_dot( ve, grind.dir ))>=k_grind_axel_min_vel) && + if( (fabsf(v3_dot( v, grind.dir ))>=k_grind_axel_min_vel) && (a >= a_min) && (fabsf(grind.dir[1]) < 0.70710678118654752f)) { @@ -509,12 +518,7 @@ static void player__approximate_best_trajectory(void){ world_tri_index_surface( trace_world, tri[0] ); inf->type = k_prediction_land; - - v3f ve; - v3_copy( launch_v, ve ); - ve[1] += -gravity * t; - - inf->score = -v3_dot( ve, inf->n ); + inf->score = -v3_dot( v, inf->n ); inf->land_dist = t + k_trace_delta * t1; /* Bias prediction towords ramps */ @@ -901,10 +905,20 @@ static void skate_apply_friction_model(void){ f32 lat = k_friction_lat; if( fabsf(axis_state(k_sraxis_skid)) > 0.1f ){ - lat = k_friction_lat * 2.0f; + if( (player_skate.surface == k_surface_prop_snow) || + (player_skate.surface == k_surface_prop_sand) ){ + lat *= 8.0f; + } + else + lat *= 1.5f; } - vel[0] += vg_cfrictf( vel[0], k_friction_lat * k_rb_delta ); + if( player_skate.surface == k_surface_prop_snow ) + lat *= 0.5f; + else if( player_skate.surface == k_surface_prop_sand ) + lat *= 0.6f; + + vel[0] += vg_cfrictf( vel[0], lat * k_rb_delta ); vel[2] += vg_cfrictf( vel[2], k_friction_resistance * k_rb_delta ); /* Pushing additive force */ @@ -1206,6 +1220,12 @@ static void player__skate_pre_update(void){ if( button_down(k_srbind_use) && (v3_length2(state->trick_vel) < 0.01f) ){ localplayer.subsystem = k_player_subsystem_walk; + if( state->activity <= k_skate_activity_air_to_grind ){ + localplayer.subsystem = k_player_subsystem_glide; + player__begin_holdout( (v3f){0,0,0} ); + return; + } + v3f angles; v3_copy( localplayer.cam.angles, localplayer.angles ); localplayer.angles[2] = 0.0f; @@ -1221,6 +1241,7 @@ static void player__skate_pre_update(void){ player__begin_holdout( offset ); player__walk_transition( state->activity <= k_skate_activity_air_to_grind? 0: 1, state->trick_euler[0] ); + return; } @@ -2352,6 +2373,11 @@ grinding:; skate_apply_trick_model(); skate_apply_pump_model(); + ent_tornado_debug(); + v3f a; + ent_tornado_forces( localplayer.rb.co, localplayer.rb.v, a ); + v3_muladds( localplayer.rb.v, a, k_rb_delta, localplayer.rb.v ); + begin_collision:; /* @@ -3407,27 +3433,37 @@ static void player__skate_pose( void *_animator, player_pose *pose ){ static void player__skate_effects( void *_animator, m4x3f *final_mtx, struct player_board *board, struct player_effects_data *effect_data ){ - struct skeleton *sk = &localplayer.skeleton; struct player_skate_animator *animator = _animator; - if( animator->grind > 0.5f ){ - v3f vp0, vp1, vpc; - if( board ){ - v3_copy((v3f){0.0f,0.02f, board->truck_positions[0][2]}, vp1 ); - v3_copy((v3f){0.0f,0.02f, board->truck_positions[1][2]}, vp0 ); - } - else{ - v3_zero( vp0 ); - v3_zero( vp1 ); - } + v3f vp0, vp1, vpc; + if( board ){ + v3_copy((v3f){0.0f,0.02f, board->truck_positions[0][2]}, vp1 ); + v3_copy((v3f){0.0f,0.02f, board->truck_positions[1][2]}, vp0 ); + } + else{ + v3_zero( vp0 ); + v3_zero( vp1 ); + } - v3f *board_mtx = final_mtx[ localplayer.id_board ]; - m4x3_mulv( board_mtx, vp0, vp0 ); - m4x3_mulv( board_mtx, vp1, vp1 ); - v3_add( vp0, vp1, vpc ); - v3_muls( vpc, 0.5f, vpc ); + v3f *board_mtx = final_mtx[ localplayer.id_board ]; + m4x3_mulv( board_mtx, vp0, vp0 ); + m4x3_mulv( board_mtx, vp1, vp1 ); + v3_add( vp0, vp1, vpc ); + v3_muls( vpc, 0.5f, vpc ); + if( animator->surface == k_surface_prop_sand ){ + if( (animator->slide>0.4f) && (v3_length2(animator->root_v)>4.0f*4.0f) ){ + v3f v, co; + v3_muls( animator->root_v, 0.5f, v ); + v3_lerp( vp0, vp1, vg_randf64(&vg.rand), co ); + + effect_data->sand.colour = 0xff8ec4e6; + effect_spark_apply( &effect_data->sand, co, v, vg.time_delta * 8.0 ); + } + } + + if( animator->grind > 0.5f ){ int back = 0, front = 0, mid = 0; if( animator->activity == k_skate_activity_grind_5050 ){ diff --git a/player_walk.c b/player_walk.c index 38429c7..9c23978 100644 --- a/player_walk.c +++ b/player_walk.c @@ -1097,7 +1097,9 @@ static void player__walk_im_gui(void){ "wood", "grass", "tiles", - "metal" } + "metal", + "snow", + "sand" } [w->surface] ); } diff --git a/skaterift.c b/skaterift.c index aa0bc8d..be4084e 100644 --- a/skaterift.c +++ b/skaterift.c @@ -195,6 +195,7 @@ static void skaterift_load_player_content(void){ replay_clear( &skaterift.replay ); particle_alloc( &particles_grind, 300 ); + particle_alloc( &particles_env, 200 ); player_load_animation_reference( "models/ch_none.mdl" ); player_model_load( &localplayer.fallback_model, "models/ch_none.mdl" ); @@ -228,6 +229,7 @@ static void vg_load(void){ vg_loader_step( addon_system_init, NULL ); vg_loader_step( workshop_init, NULL ); vg_loader_step( skateshop_init, NULL ); + vg_loader_step( ent_tornado_init, NULL ); vg_loader_step( skaterift_load_player_content, NULL ); @@ -501,6 +503,11 @@ static void render_scene(void){ //particle_system_debug( &particles_grind ); particle_system_prerender( &particles_grind ); particle_system_render( &particles_grind, &skaterift.cam ); + + ent_tornado_pre_update(); + particle_system_update( &particles_env, vg.time_delta ); + particle_system_prerender( &particles_env ); + particle_system_render( &particles_env, &skaterift.cam ); /* * render transition