So far this is the best result I could get right now
Code:
#include <acknex.h>
#include <default.c>

#define PRAGMA_POINTER

// default trace/move flags
#define TRACE_FLAGS (IGNORE_ME | IGNORE_PASSABLE | IGNORE_PASSENTS | IGNORE_MAPS | IGNORE_SPRITES | IGNORE_CONTENT)
#define MOVE_FLAGS (IGNORE_ME | IGNORE_PASSABLE | IGNORE_PASSENTS | IGNORE_MAPS | IGNORE_SPRITES | IGNORE_CONTENT)

// collusion groups/push values
#define PUSH_GROUP							2
#define SWITCH_ITEM_GROUP						3
#define PATHFIND_GROUP							4
#define PLAYER_GROUP							5
#define TRAPS_GROUP							6
#define OBSTACLE_GROUP							7

#define LEVEL_GROUP							10

// vectors
#define speed_x								skill50
#define speed_y								skill51
#define speed_z								skill52

#define obj_soil_contact						skill69

// character controller (CCT) global parameters
var cct_gravity = 4;							// gravity strength
var cct_gravity_max = 90;						// gravity max strength

MATERIAL* mtlWireframe = {
	
	effect = "
	float4x4 matWorldViewProj;
	
	void VS (in float4 InPos	: POSITION, out float4 OutPos	: POSITION) {
		OutPos = mul(InPos, matWorldViewProj);
	}
	
	float4 PS() : COLOR0 {
		return float4( 1.0f, 1.0f, 0.0f, 1.0f );
	}
	
	technique t0 {
		pass p0 {
			FillMode = Wireframe;
			VertexShader = compile vs_2_0 VS();
			PixelShader  = compile ps_2_0 PS();
		}
	}
	";
	
}

// calculate bounce vector
void get_bounce(VECTOR *speed, VECTOR *bounce_vec){
	
	VECTOR temp_inverse;
	vec_set(&temp_inverse, speed);
	vec_inverse(&temp_inverse);
	
	bounce_vec->x = speed->x + 2 * vec_dot(&normal, &temp_inverse) * normal.x;
	bounce_vec->y = speed->y + 2 * vec_dot(&normal, &temp_inverse) * normal.y;
	bounce_vec->z = speed->z + 2 * vec_dot(&normal, &temp_inverse) * normal.z;
	
}

// gravity trace for all npc
void prop_gravity(ENTITY *ent, var *z_force, var *soil, var offset){
	
	if(!ent){ return; }
	
	// gravity
	if(*z_force <= 0){
		
		VECTOR temp, target_vec;
		vec_set(&temp, vector(ent->x, ent->y, ent->z - 150 + offset));
		c_trace(&ent->x, &temp, TRACE_FLAGS | USE_BOX);
		
		vec_set(&target_vec, &temp);		
		if(HIT_TARGET){ vec_set(&target_vec, &target); }		
		*soil = target_vec.z - offset;
		
	}
	
	// additional height buffer when ground contact to avoid player floating on slopes
	if(ent->z > *soil + (5 + 20 * ent->obj_soil_contact) * time_step || *z_force > 0){
		
		ent->obj_soil_contact = 0;
		*z_force = maxv(*z_force - 9 * time_step, -90);
		
	}
	else{
		
		c_move(ent, nullvector, vector(0, 0, *soil - ent->z), MOVE_FLAGS);
		ent->obj_soil_contact = 1;
		*z_force = 0;
		
	}
	
	if(*z_force){
		
		// the maxv command makes sure you never move below the desired height
		c_move(ent, nullvector, vector(0, 0, maxv(*z_force * time_step, *soil - ent->z)), MOVE_FLAGS);
		
	}
	
}

action grenade(){
	
	c_setminmax(my);
	set(my, SHADOW | POLYGON);
	
	VECTOR velocity;
	vec_set(&velocity, vector(25, 0, 5));
	vec_rotate(&velocity, &camera->pan);
	
	var soil_height = 0;		// target height from surface bellow
	var gravity = 5;		// 1 - 10 (default 5)
	var restitution = 0.5;		// 0.1 - 0.9 (default - 0.5)
	var hit_count = 0;
	var counter = 0;
	
	while(my){
		
		// still got go bounce ?
		if(hit_count < 5){
			
			VECTOR temp;
			vec_set(&temp, &velocity);
			vec_scale(&temp, time_step);
			c_move(my, nullvector, &temp, MOVE_FLAGS);
			
			velocity.z -= gravity * time_step;
			
			if(HIT_TARGET){
				
				hit_count++;
				
				VECTOR bounce_vec;
				get_bounce(&velocity, &bounce_vec);
				var speed = vec_length(&velocity);
				vec_set(&velocity, &bounce_vec);
				vec_normalize(&velocity, restitution * speed);
				
			}
			
		}
		else{
			
			// reset all movement
			vec_fill(&velocity, 0);
			
			// simple gravity ?
			prop_gravity(my, &my->speed_z, &soil_height, my->min_z);
			
		}
		
		counter += time_frame / 16;
		if(counter >= 3){ break; }
		
		wait(1);
		
	}
	
	safe_remove(my);
	
}

void main(){
	
	shadow_stencil = 2;
	
	fps_max = 60;
	warn_level = 6;
	level_load("");
	wait(3);
	
	camera->arc = 90;
	vec_set(&camera->x, vector(-439, 0, 323));
	vec_set(&camera->pan, vector(0, -36, 0));
	
	level_ent = ent_create(CUBE_MDL, nullvector, NULL);
	vec_set(&level_ent->scale_x, vector(256, 256, 0.1));
	c_setminmax(level_ent);
	set(level_ent, POLYGON | SHADOW);
	//level_ent->material = mtlWireframe;
	
	ENTITY *wall = ent_create(CUBE_MDL, vector(0, 256, 64), NULL);
	vec_set(&wall->scale_x, vector(4, 8, 8));
	c_setminmax(wall);
	set(wall, POLYGON | SHADOW);
	//wall->material = mtlWireframe;
	
	int i = 0;	
	var counter = 0, throw = 0;
	
	while(!key_esc){
		
		if(mouse_left){
			
			if(throw == 0){
				
				ent_create(CUBE_MDL, &camera->x, grenade);
				
				throw = 1;
				
			}
			
		}
		
		if(throw == 1){
			
			counter += time_frame / 16;
			if(counter > 0.5){ throw = 0; counter -= 0.5; }
			
		}
		
		// slow down framerate for testing
		if(key_e){ fps_max = 20; }
		else{ fps_max = 60; }
		
		DEBUG_VAR(fps_max, 0);
		
		wait(1);
		
	}

}



Looking for free stuff?? Take a look here: http://badcom.at.ua
Support me on: https://boosty.to/3rung