#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);
}
}