mirror of
https://github.com/nzp-team/quakec.git
synced 2025-04-14 05:51:46 +00:00
Adds V3 AI animation driver logic
Fixes sv navmesh loading Adds closed door checking to sv navmesh Adds min / max util math functions Removes entrance_edge from navmesh polygons
This commit is contained in:
parent
09563f8670
commit
47188f6632
8 changed files with 413 additions and 588 deletions
|
@ -246,24 +246,24 @@ void cl_navmesh_draw_poly(float poly_index) {
|
|||
}
|
||||
|
||||
// If polygon's entrance edge is set, draw other edges as red.
|
||||
if(cl_navmesh_polies[poly_index].entrance_edge != -1) {
|
||||
for(int i = 0; i < cl_navmesh_polies[poly_index].vert_count; i++) {
|
||||
if(i == cl_navmesh_polies[poly_index].entrance_edge)
|
||||
continue;
|
||||
// if(cl_navmesh_polies[poly_index].entrance_edge != -1) {
|
||||
// for(int i = 0; i < cl_navmesh_polies[poly_index].vert_count; i++) {
|
||||
// if(i == cl_navmesh_polies[poly_index].entrance_edge)
|
||||
// continue;
|
||||
|
||||
// Draw this edge as solid red
|
||||
int edge_vert_a_idx = i;
|
||||
int edge_vert_b_idx = (i + 1) % cl_navmesh_polies[poly_index].vert_count;
|
||||
int edge_vert_a = cl_navmesh_polies[poly_index].verts[edge_vert_a_idx];
|
||||
int edge_vert_b = cl_navmesh_polies[poly_index].verts[edge_vert_b_idx];
|
||||
vector start = cl_navmesh_verts[edge_vert_a].pos;
|
||||
vector end = cl_navmesh_verts[edge_vert_b].pos;
|
||||
// // Draw this edge as solid red
|
||||
// int edge_vert_a_idx = i;
|
||||
// int edge_vert_b_idx = (i + 1) % cl_navmesh_polies[poly_index].vert_count;
|
||||
// int edge_vert_a = cl_navmesh_polies[poly_index].verts[edge_vert_a_idx];
|
||||
// int edge_vert_b = cl_navmesh_polies[poly_index].verts[edge_vert_b_idx];
|
||||
// vector start = cl_navmesh_verts[edge_vert_a].pos;
|
||||
// vector end = cl_navmesh_verts[edge_vert_b].pos;
|
||||
|
||||
vector edge_color = [0.9,0.2,0.2];
|
||||
float edge_alpha = 0.7;
|
||||
cl_navmesh_draw_line(start,end,2,edge_color,edge_alpha);
|
||||
}
|
||||
}
|
||||
// vector edge_color = [0.9,0.2,0.2];
|
||||
// float edge_alpha = 0.7;
|
||||
// cl_navmesh_draw_line(start,end,2,edge_color,edge_alpha);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -315,9 +315,9 @@ void cl_navmesh_draw_traversal(float traversal_index) {
|
|||
float edge_width = 0.1;
|
||||
|
||||
if(cl_navmesh_selected_traversal != traversal_index) {
|
||||
active_alpha = 0.2;
|
||||
active_alpha = 0.4;
|
||||
inactive_alpha = 0.0;
|
||||
edge_alpha = 0.1;
|
||||
edge_alpha = 0.4;
|
||||
edge_color = '0 0.2 0.5';
|
||||
active_color = '0 0.2 0.5';
|
||||
}
|
||||
|
@ -1115,7 +1115,7 @@ void cl_navmesh_make_poly()
|
|||
cl_navmesh_polies[cl_navmesh_poly_count].verts[i] = selected_verts[i];
|
||||
}
|
||||
cl_navmesh_polies[cl_navmesh_poly_count].vert_count = selected_vert_count;
|
||||
cl_navmesh_polies[cl_navmesh_poly_count].entrance_edge = -1;
|
||||
// cl_navmesh_polies[cl_navmesh_poly_count].entrance_edge = -1;
|
||||
cl_navmesh_poly_count++;
|
||||
}
|
||||
|
||||
|
@ -1133,7 +1133,7 @@ void cl_navmesh_delete_poly_at_index(float poly_index)
|
|||
}
|
||||
|
||||
// Copy down other fields:
|
||||
cl_navmesh_polies[i].entrance_edge = cl_navmesh_polies[i+1].entrance_edge;
|
||||
// cl_navmesh_polies[i].entrance_edge = cl_navmesh_polies[i+1].entrance_edge;
|
||||
cl_navmesh_polies[i].doortarget = cl_navmesh_polies[i+1].doortarget;
|
||||
|
||||
}
|
||||
|
@ -1143,7 +1143,7 @@ void cl_navmesh_delete_poly_at_index(float poly_index)
|
|||
{
|
||||
cl_navmesh_polies[cl_navmesh_poly_count-1].verts[j] = -1;
|
||||
}
|
||||
cl_navmesh_polies[cl_navmesh_poly_count-1].entrance_edge = -1;
|
||||
// cl_navmesh_polies[cl_navmesh_poly_count-1].entrance_edge = -1;
|
||||
cl_navmesh_polies[cl_navmesh_poly_count-1].doortarget = "";
|
||||
|
||||
cl_navmesh_poly_count--;
|
||||
|
@ -1695,7 +1695,7 @@ void cl_navmesh_editor_save_navmesh() {
|
|||
|
||||
|
||||
// Getting polygon entrance edge index
|
||||
fputs(file,itos(cl_navmesh_polies[i].entrance_edge),"\n");
|
||||
// fputs(file,itos(cl_navmesh_polies[i].entrance_edge),"\n");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -1773,7 +1773,7 @@ void cl_navmesh_editor_clear_navmesh()
|
|||
|
||||
cl_navmesh_polies[i].doortarget = "";
|
||||
|
||||
cl_navmesh_polies[i].entrance_edge = -1;
|
||||
// cl_navmesh_polies[i].entrance_edge = -1;
|
||||
}
|
||||
cl_navmesh_traversal_count = 0;
|
||||
for(float i = 0; i < NAV_MAX_TRAVERSALS; i++) {
|
||||
|
@ -1805,19 +1805,17 @@ void cl_navmesh_editor_load_navmesh() {
|
|||
}
|
||||
|
||||
|
||||
float v;
|
||||
//First line contains navmesh file semver
|
||||
// First line contains navmesh file semver
|
||||
string nav_file_version = fgets(file);
|
||||
print("Loading v", nav_file_version, " navmesh file \"", filepath, "\"...\n");
|
||||
|
||||
// TODO - Add backwards compatibility for older navmesh file versions.
|
||||
|
||||
// Next line contains vertex count
|
||||
string line = fgets(file);
|
||||
float vert_count = stof(line);
|
||||
float vert_count = stof(fgets(file));
|
||||
|
||||
if(vert_count > NAV_MAX_VERTS) {
|
||||
print("Error: navmesh file \"",filepath,"\" has an invalid vert count. (" , line, " > ", ftos(NAV_MAX_VERTS),").\n");
|
||||
print("Error: navmesh file \"",filepath,"\" has an invalid vert count. (" , vert_count, " > ", ftos(NAV_MAX_VERTS),").\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
@ -1826,20 +1824,12 @@ void cl_navmesh_editor_load_navmesh() {
|
|||
cl_navmesh_editor_clear_navmesh();
|
||||
|
||||
cl_navmesh_vert_count = vert_count;
|
||||
|
||||
print("Vert count: ",line,"\n");
|
||||
print("Vert count: ",vert_count,"\n");
|
||||
|
||||
|
||||
//Temp vector to assign component-wise
|
||||
vector temp;
|
||||
|
||||
//Reading all of the vertex positions
|
||||
for(float i = 0; i < cl_navmesh_vert_count; i++) {
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
cl_navmesh_verts[i].pos.x = temp.x;
|
||||
cl_navmesh_verts[i].pos.y = temp.y;
|
||||
cl_navmesh_verts[i].pos.z = temp.z;
|
||||
//TODO: if something goes wrong, clear the partially loaded navmesh
|
||||
cl_navmesh_verts[i].pos = stov(fgets(file));
|
||||
}
|
||||
|
||||
//Next line contains the number of polygons
|
||||
|
@ -1881,7 +1871,7 @@ void cl_navmesh_editor_load_navmesh() {
|
|||
|
||||
// If navmesh file version 0.0.0, no traversals
|
||||
// FIXME - Need a better way to do this..
|
||||
if(strcmp(nav_file_version, "0.0.0") != 0) {
|
||||
if(nav_file_version != "0.0.0") {
|
||||
// Don't care about connected traversals
|
||||
float n_traversals = stof(fgets(file));
|
||||
for(float j = 0; j < n_traversals; j++) {
|
||||
|
@ -1896,8 +1886,11 @@ void cl_navmesh_editor_load_navmesh() {
|
|||
print("CLLOADNAVMESH - Polygon at index ",ftos(i)," has doortarget: \"", cl_navmesh_polies[i].doortarget, "\"" );
|
||||
}
|
||||
// cl_navmesh_polies[i].doortarget = ""; // Temp fix to load old files
|
||||
// Load entrance edge
|
||||
cl_navmesh_polies[i].entrance_edge = stoi(fgets(file));
|
||||
// If v0.0.0, discard entrance edge (no longer used)
|
||||
if(nav_file_version == "0.0.0") {
|
||||
// cl_navmesh_polies[i].entrance_edge = stoi(fgets(file));
|
||||
fgets(file);
|
||||
}
|
||||
// cl_navmesh_polies[i].entrance_edge = -1; // Temp fix to load old files
|
||||
}
|
||||
|
||||
|
@ -1905,27 +1898,15 @@ void cl_navmesh_editor_load_navmesh() {
|
|||
// Load Traversals
|
||||
// -----------------------------------------------------------------------
|
||||
// If navmesh file version 0.0.0, no traversals
|
||||
if(strcmp(nav_file_version, "0.0.0") != 0) {
|
||||
if(nav_file_version != "0.0.0") {
|
||||
// Next line contains the number of traverals
|
||||
cl_navmesh_traversal_count = stof(fgets(file));
|
||||
|
||||
// Next lines are each traversal
|
||||
for(float i = 0; i < cl_navmesh_traversal_count; i++) {
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
cl_navmesh_traversals[i].start_pos.x = temp.x;
|
||||
cl_navmesh_traversals[i].start_pos.y = temp.y;
|
||||
cl_navmesh_traversals[i].start_pos.z = temp.z;
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
cl_navmesh_traversals[i].midpoint_pos.x = temp.x;
|
||||
cl_navmesh_traversals[i].midpoint_pos.y = temp.y;
|
||||
cl_navmesh_traversals[i].midpoint_pos.z = temp.z;
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
cl_navmesh_traversals[i].end_pos.x = temp.x;
|
||||
cl_navmesh_traversals[i].end_pos.y = temp.y;
|
||||
cl_navmesh_traversals[i].end_pos.z = temp.z;
|
||||
cl_navmesh_traversals[i].start_pos = stov(fgets(file));
|
||||
cl_navmesh_traversals[i].midpoint_pos = stov(fgets(file));
|
||||
cl_navmesh_traversals[i].end_pos = stov(fgets(file));
|
||||
cl_navmesh_traversals[i].angle = stof(fgets(file));
|
||||
cl_navmesh_traversals[i].use_midpoint = stof(fgets(file));
|
||||
// Don't care about traversal end polygon index
|
||||
|
@ -2620,6 +2601,9 @@ void cl_pathfind_trace_path(float start_poly, float goal_poly) {
|
|||
//Returns 1 on success.
|
||||
//Returns 0 on fail.
|
||||
float cl_navmesh_pathfind_start(float start_poly, float goal_poly, vector start_pos, vector end_pos) {
|
||||
//Clearing previous data
|
||||
cl_pathfind_clear_result_data();
|
||||
|
||||
if(start_poly == -1) {
|
||||
print("Error: pathfind start node invalid.\n");
|
||||
return 0;
|
||||
|
@ -2645,9 +2629,6 @@ float cl_navmesh_pathfind_start(float start_poly, float goal_poly, vector start_
|
|||
return 1;
|
||||
}
|
||||
|
||||
//Clearing previous data
|
||||
cl_pathfind_clear_result_data();
|
||||
|
||||
//Adding start polygon to the open set
|
||||
cl_test_pathfind_result->poly_set[start_poly] = PATHFIND_POLY_SET_OPEN;
|
||||
cl_test_pathfind_result->poly_g_score[start_poly] = 0;
|
||||
|
@ -2693,67 +2674,6 @@ float cl_navmesh_pathfind_start(float start_poly, float goal_poly, vector start_
|
|||
// NOTE - This check isn't done in the navmesh editor.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// // ----------------------------------------------------------------
|
||||
// // Entrance edge
|
||||
// // ----------------------------------------------------------------
|
||||
// // Check if we can enter this polygon from this edge
|
||||
// // If entrance_edge != -1, we can only enter the polygon from the edge at index "entrance_edge"
|
||||
// if(cl_navmesh_polies[neighbor].entrance_edge != -1) {
|
||||
// // print("-- Pathfind loop -- Evaluating a neighbor whose entrance_edge = ",ftos(cl_navmesh_polies[neighbor].entrance_edge),"\n");
|
||||
// // print("Current polygon:",ftos(current),"\n");
|
||||
// // print("Neighbor polygon:",ftos(neighbor),"\n");
|
||||
// // print("Neighbor index:",ftos(i),"\n");
|
||||
// // print("Current vertices: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[current].vert_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[current].verts[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("Neighbor vertices: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[neighbor].vert_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[neighbor].verts[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("Current left portal vertices: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[current].connected_polies_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[current].connected_polies_left_vert[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("Current right portal vertices: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[current].connected_polies_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[current].connected_polies_right_vert[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("neighbor left portal vertices: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[neighbor].connected_polies_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[neighbor].connected_polies_left_vert[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("neighbor right portal vertices: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[neighbor].connected_polies_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[neighbor].connected_polies_right_vert[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("Current neighbor edge index: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[current].connected_polies_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[current].connected_polies_neighbor_edge_index[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("Neighbor neighbor edge index: ");
|
||||
// // for(float j = 0; j < cl_navmesh_polies[neighbor].connected_polies_count; j++) {
|
||||
// // print(ftos(cl_navmesh_polies[neighbor].connected_polies_neighbor_edge_index[j]),",");
|
||||
// // }
|
||||
// // print("\n");
|
||||
// // print("According to current polygon, the we're traversing the neighbor's edge with index: ", ftos(cl_navmesh_polies[current].connected_polies_neighbor_edge_index[i])," to enter neighbor.\n");
|
||||
|
||||
// // Check if the edge we're crossing from current to neighbor is the entrance edge
|
||||
// if(cl_navmesh_polies[neighbor].entrance_edge != cl_navmesh_polies[current].connected_polies_neighbor_edge_index[i]) {
|
||||
// // If it's not the entrance edge, skip this neighbor.
|
||||
// // We can't walk from current to neighbor.
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
// // ----------------------------------------------------------------
|
||||
|
||||
|
||||
if(cl_test_pathfind_result->poly_set[neighbor_poly] != PATHFIND_POLY_SET_CLOSED) {
|
||||
//print("Neighbor is not in closed list.\n");
|
||||
|
@ -3086,7 +3006,7 @@ void cl_register_navmesh_commands() =
|
|||
registercommand("yes");
|
||||
registercommand("nav_load_navmesh");
|
||||
registercommand("nav_toggle_poly_door");
|
||||
registercommand("nav_toggle_poly_entrance_edge");
|
||||
// registercommand("nav_toggle_poly_entrance_edge");
|
||||
registercommand("nav_print_poly_door");
|
||||
|
||||
// --- Traversal Commands ---
|
||||
|
@ -3121,7 +3041,8 @@ void cl_navmesh_editor_toggle_poly_door() {
|
|||
string editor_active_door = strcat(cvar_string("nav_editor_active_door"));
|
||||
|
||||
// If current polygon doortarget isn't set to the editor's currently active door, set it
|
||||
if(strcmp(cl_navmesh_polies[selected_polygon].doortarget, editor_active_door) != 0) {
|
||||
// if(strcmp(cl_navmesh_polies[selected_polygon].doortarget, editor_active_door) != 0) {
|
||||
if(cl_navmesh_polies[selected_polygon].doortarget != editor_active_door) {
|
||||
cl_navmesh_polies[selected_polygon].doortarget = editor_active_door;
|
||||
}
|
||||
// Otherwise, clear it.
|
||||
|
@ -3151,23 +3072,23 @@ void cl_navmesh_editor_print_poly_door() {
|
|||
}
|
||||
|
||||
|
||||
void cl_navmesh_editor_toggle_entrance_edge() {
|
||||
int selected_polygon = cl_navmesh_get_selected_poly();
|
||||
if(selected_polygon == -1) {
|
||||
print("Can't make door polygon. No polygon selected.\n");
|
||||
return;
|
||||
}
|
||||
// void cl_navmesh_editor_toggle_entrance_edge() {
|
||||
// int selected_polygon = cl_navmesh_get_selected_poly();
|
||||
// if(selected_polygon == -1) {
|
||||
// print("Can't make door polygon. No polygon selected.\n");
|
||||
// return;
|
||||
// }
|
||||
|
||||
cl_navmesh_polies[selected_polygon].entrance_edge += 1;
|
||||
// If entrance edge index is no longer valid, reset it to -1
|
||||
if(cl_navmesh_polies[selected_polygon].entrance_edge >= cl_navmesh_polies[selected_polygon].vert_count) {
|
||||
cl_navmesh_polies[selected_polygon].entrance_edge = -1;
|
||||
}
|
||||
// cl_navmesh_polies[selected_polygon].entrance_edge += 1;
|
||||
// // If entrance edge index is no longer valid, reset it to -1
|
||||
// if(cl_navmesh_polies[selected_polygon].entrance_edge >= cl_navmesh_polies[selected_polygon].vert_count) {
|
||||
// cl_navmesh_polies[selected_polygon].entrance_edge = -1;
|
||||
// }
|
||||
|
||||
print("Selected Polygon entrance edge set to: ");
|
||||
print(itos(cl_navmesh_polies[selected_polygon].entrance_edge));
|
||||
print("\n");
|
||||
}
|
||||
// print("Selected Polygon entrance edge set to: ");
|
||||
// print(itos(cl_navmesh_polies[selected_polygon].entrance_edge));
|
||||
// print("\n");
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
@ -3579,21 +3500,21 @@ float(string cmd) cl_navmesh_console_commands =
|
|||
case "nav_print_poly_door":
|
||||
cl_navmesh_editor_print_poly_door();
|
||||
return TRUE;
|
||||
case "nav_toggle_poly_entrance_edge":
|
||||
cl_navmesh_editor_toggle_entrance_edge();
|
||||
// TODO - Make currently selected polygon only be traversible from
|
||||
// TODO one direction to another.
|
||||
// TODO
|
||||
// TODO - If no polygon selected, stop.
|
||||
// TODO - If Quad, assume verts sorted CCW from BL
|
||||
// TODO - if not one-way, make one-way poly from 01 to 23
|
||||
// TODO - if one-way from 01 to 23, make one-way from 12 to 03
|
||||
// TODO - if one-way from 12 to 03, make one-way from 23 to 01
|
||||
// TODO - if one-way from 12 to 03, make one-way from 03 to 12
|
||||
// TODO - if one-way from 03 to 12, make normal polygon
|
||||
// TODO - If tri, should I support one-way? (probably not, tbh)
|
||||
// TODO
|
||||
return TRUE;
|
||||
// case "nav_toggle_poly_entrance_edge":
|
||||
// cl_navmesh_editor_toggle_entrance_edge();
|
||||
// // TODO - Make currently selected polygon only be traversible from
|
||||
// // TODO one direction to another.
|
||||
// // TODO
|
||||
// // TODO - If no polygon selected, stop.
|
||||
// // TODO - If Quad, assume verts sorted CCW from BL
|
||||
// // TODO - if not one-way, make one-way poly from 01 to 23
|
||||
// // TODO - if one-way from 01 to 23, make one-way from 12 to 03
|
||||
// // TODO - if one-way from 12 to 03, make one-way from 23 to 01
|
||||
// // TODO - if one-way from 12 to 03, make one-way from 03 to 12
|
||||
// // TODO - if one-way from 03 to 12, make normal polygon
|
||||
// // TODO - If tri, should I support one-way? (probably not, tbh)
|
||||
// // TODO
|
||||
// return TRUE;
|
||||
case "nav_place_traversal":
|
||||
cl_navmesh_editor_place_traversal();
|
||||
return TRUE;
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
|
||||
|
||||
|
||||
// FIXME - This framegroup nonsense is causing chaos... the struct is too large apparently... what can I cut out?
|
||||
|
||||
|
||||
void init_framegroup( float start_frame, float end_frame, float duration,
|
||||
void(entity) frame_callback,
|
||||
void(entity) think_callback,
|
||||
__out framegroup fg) {
|
||||
fg.start_frame = start_frame;
|
||||
fg.end_frame = end_frame;
|
||||
fg.duration = duration;
|
||||
fg.frame_callback = frame_callback;
|
||||
fg.think_callback = think_callback;
|
||||
}
|
||||
DEFINE_ANIM(zombie_idle, 1,2,3,4,5,6,7,8,9,10,11,12,13); // Defines: get_anim_frame_zombie_idle, get_anim_length_zombie_idle
|
||||
DEFINE_ANIM(zombie_rise, 14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37); // Defines: get_anim_frame_zombie_rise, get_anim_length_zombie_rise
|
||||
DEFINE_ANIM(zombie_walk1, 38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53); // Defines: get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1
|
||||
DEFINE_ANIM(zombie_walk2, 54,55,56,57,58,59,60,61,62,63,64,65,66,67); // Defines: get_anim_frame_zombie_walk2, get_anim_length_zombie_walk2
|
||||
DEFINE_ANIM(zombie_walk3, 68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83); // Defines: get_anim_frame_zombie_walk3, get_anim_length_zombie_walk3
|
||||
DEFINE_ANIM(zombie_jog1, 84,85,86,87,88,89,90,91,92); // Defines: get_anim_frame_zombie_jog1, get_anim_length_zombie_jog1
|
||||
DEFINE_ANIM(zombie_run1, 93,94,95,96,97,98,99,100,101,102); // Defines: get_anim_frame_zombie_run1, get_anim_length_zombie_run1
|
||||
DEFINE_ANIM(zombie_attack1, 103,104,105,106,107); // Defines: get_anim_frame_zombie_attack1, get_anim_length_zombie_attack1
|
||||
DEFINE_ANIM(zombie_attack2, 108,109,110,111,112,113); // Defines: get_anim_frame_zombie_attack2, get_anim_length_zombie_attack2
|
||||
DEFINE_ANIM(zombie_window_rip_board1, 182,183,184,185,186,187,188,189,190,191,192); // Defines: get_anim_frame_zombie_window_rip_board1, get_anim_length_zombie_window_rip_board1
|
||||
DEFINE_ANIM(zombie_window_rip_board2, 192,193,194,195,196,197,198,199,200,201,202); // Defines: get_anim_frame_zombie_window_rip_board2, get_anim_length_zombie_window_rip_board2
|
||||
DEFINE_ANIM(zombie_window_attack, 202,203,204,205,206,207,208,209,210,211); // Defines: get_anim_frame_zombie_window_attack, get_anim_length_zombie_window_attack
|
||||
DEFINE_ANIM(zombie_window_hop, 114,115,116,117,118,119,120,121,122,123); // Defines: get_anim_frame_zombie_window_hop, get_anim_length_zombie_window_hop
|
||||
DEFINE_ANIM(zombie_die1, 124,125,126,127,128,129,130,131,132,133,134); // Defines: get_anim_frame_zombie_die1, get_anim_length_zombie_die1
|
||||
DEFINE_ANIM(zombie_die2, 135,136,137,138,139); // Defines: get_anim_frame_zombie_die2, get_anim_length_zombie_die2
|
||||
DEFINE_ANIM(zombie_die3, 140,141,142,143,144,145,146,147,148,149); // Defines: get_anim_frame_zombie_die3, get_anim_length_zombie_die3
|
||||
DEFINE_ANIM(zombie_die_wunder, 212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228); // Defines: get_anim_frame_zombie_die_wunder, get_anim_length_zombie_die_wunder
|
||||
DEFINE_ANIM(zombie_fall, 150,151,152,153); // Defines: get_anim_frame_zombie_fall, get_anim_length_zombie_fall
|
||||
DEFINE_ANIM(zombie_land, 154,155,156,157,158,159,160); // Defines: get_anim_frame_zombie_land, get_anim_length_zombie_land
|
||||
DEFINE_ANIM(zombie_jump, 161,162,163,164,165,166,167); // Defines: get_anim_frame_zombie_jump, get_anim_length_zombie_jump
|
||||
DEFINE_ANIM(zombie_climb, 168,169,170,171,172,173,174,175,176,177,178,179,180,181,182); // Defines: get_anim_frame_zombie_climb, get_anim_length_zombie_climb
|
||||
|
||||
|
||||
|
||||
|
@ -22,140 +27,73 @@ void() AI_Chase::AI_Chase = {
|
|||
this.path_target = world;
|
||||
this.path_pos = world.origin;
|
||||
this.think_delta_time = 0.1; // Call `this.think();` 10x per second
|
||||
this.cur_fg_idx = 0;
|
||||
};
|
||||
|
||||
|
||||
void() AI_Chase::think = {
|
||||
if(this.cur_fg_start_time >= 0) {
|
||||
float cur_framegroup_idx = this.cur_fg_idx;
|
||||
float dt = time - this.cur_fg_start_time;
|
||||
float lerp_frac = (dt / this.cur_fg_duration);
|
||||
// Frame ranges are inclusive, do an un-clamped interpolation to include the final frame
|
||||
float cur_frame = unclamped_lerp(this.cur_fg_start_frame, this.cur_fg_end_frame, lerp_frac);
|
||||
// For rendering, keep frame number always within current animation
|
||||
if(this.cur_fg_end_frame > this.cur_fg_start_frame) {
|
||||
this.frame = clamp(cur_frame, this.cur_fg_start_frame, this.cur_fg_end_frame);
|
||||
}
|
||||
else {
|
||||
this.frame = clamp(cur_frame, this.cur_fg_end_frame, this.cur_fg_start_frame);
|
||||
}
|
||||
|
||||
// print("Cur frame: ");
|
||||
// print(ftos(this.frame));
|
||||
// print(", start_frame: ");
|
||||
// print(ftos(this.cur_fg_start_frame));
|
||||
// print(", end_frame: ");
|
||||
// print(ftos(this.cur_fg_end_frame));
|
||||
// print(", cur_frame: ");
|
||||
// print(ftos(cur_frame));
|
||||
// print(", next frame callback: ");
|
||||
// print(ftos(this.cur_fg_frame_callback_next_frame));
|
||||
// print(", duration: ");
|
||||
// print(ftos(this.cur_fg_duration));
|
||||
// print("\n");
|
||||
// ------------------------------------------------------------------------
|
||||
// Animation logic
|
||||
// ------------------------------------------------------------------------
|
||||
float cur_anim_prev_frame_idx = floor(this.cur_anim_frame_idx);
|
||||
|
||||
// TODO - round frame to nearest frame?
|
||||
// Check if we're updating the current animation being played
|
||||
if(this.cur_anim_get_frame_func != SUB_Null) {
|
||||
this.cur_anim_frame_idx = (time - this.cur_anim_start_time) / this.cur_anim_frametime;
|
||||
|
||||
// If the animation is playing forward (low frame num to high frame num)
|
||||
if(this.cur_fg_end_frame > this.cur_fg_start_frame) {
|
||||
if(cur_frame >= this.cur_fg_frame_callback_next_frame) {
|
||||
if(cur_frame >= this.cur_fg_end_frame + 1) {
|
||||
this.cur_fg_frame_callback_is_end_frame = true;
|
||||
}
|
||||
this.cur_fg_frame_callback(this); // FIXME - This can override and invoke new things, need to be careful
|
||||
// Callback may have assigned new framegroup
|
||||
if(this.cur_fg_idx == cur_framegroup_idx) {
|
||||
this.cur_fg_frame_callback_is_start_frame = false;
|
||||
this.cur_fg_frame_callback_is_end_frame = false;
|
||||
this.cur_fg_frame_callback_next_frame = floor(cur_frame) + 1;
|
||||
}
|
||||
// print("\tSet next frame callback frame to: ");
|
||||
// print(ftos(this.cur_fg_frame_callback_next_frame));
|
||||
// print("\n");
|
||||
// If at the final frame, we're done
|
||||
if(this.cur_anim_frame_idx >= this.cur_anim_length) {
|
||||
if(this.cur_anim_stop_type == ANIM_STOP_TYPE_LOOP) {
|
||||
this.cur_anim_frame_idx = this.cur_anim_frame_idx % this.cur_anim_length;
|
||||
}
|
||||
else if(this.cur_anim_stop_type == ANIM_STOP_TYPE_NEXT_ANIM) {
|
||||
this.play_anim(
|
||||
this.next_anim_get_frame_func,
|
||||
this.next_anim_length,
|
||||
this.next_anim_stop_type);
|
||||
this.cur_anim_frametime = this.next_anim_frametime;
|
||||
// We started a new animation, play the frame callback
|
||||
cur_anim_prev_frame_idx = -1;
|
||||
}
|
||||
// Otherwise, treat it as ANIM_STOP_TYPE_STOP
|
||||
else {
|
||||
this.cur_anim_frame_idx = min(this.cur_anim_frame_idx, this.cur_anim_length - 1);
|
||||
this.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
||||
this.cur_anim_length = 0;
|
||||
}
|
||||
}
|
||||
// else the animation is playing in reverse (high frame num to low frame num)
|
||||
else {
|
||||
if(cur_frame <= this.cur_fg_frame_callback_next_frame) {
|
||||
if(cur_frame <= this.cur_fg_end_frame - 1) {
|
||||
this.cur_fg_frame_callback_is_end_frame = true;
|
||||
}
|
||||
this.cur_fg_frame_callback(this);
|
||||
// Callback may have assigned new framegroup
|
||||
if(this.cur_fg_idx == cur_fg_idx) {
|
||||
this.cur_fg_frame_callback_is_start_frame = false;
|
||||
this.cur_fg_frame_callback_is_end_frame = false;
|
||||
this.cur_fg_frame_callback_next_frame = ceil(cur_frame) - 1;
|
||||
}
|
||||
|
||||
// If we still have an animation:
|
||||
if(this.cur_anim_get_frame_func != SUB_Null) {
|
||||
// NOTE - We can control frame interpolation using the fractional
|
||||
// NOTE portion of `cur_anim_frame_idx`, in case we ever have
|
||||
// NOTE better control over MDL frame interpolation.
|
||||
this.cur_anim_frame_idx = floor(this.cur_anim_frame_idx);
|
||||
this.frame = this.cur_anim_get_frame_func(this.cur_anim_frame_idx);
|
||||
|
||||
if(floor(this.cur_anim_frame_idx) != cur_anim_prev_frame_idx) {
|
||||
this.frame_callback();
|
||||
}
|
||||
}
|
||||
// Callback may have assigned new framegroup
|
||||
// if(this.cur_fg_idx == cur_fg_idx) {
|
||||
this.cur_fg_think_callback(this);
|
||||
// }
|
||||
// print("Frame_idx: ", ftos(this.cur_anim_frame_idx), " Actual frame: ", ftos(this.frame), "\n");
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
this.nextthink = time + this.think_delta_time;
|
||||
};
|
||||
|
||||
void (float duration) AI_Chase::set_framegroup_duration = {
|
||||
// If no current framegroup, stop
|
||||
if(this.cur_fg_start_time < 0) {
|
||||
print("Warning: Attempted to set framegroup duration without an active framegroup.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
this.cur_fg_duration = duration;
|
||||
// --------------------------------------------------------------------
|
||||
// Adjust think_delta_time so no frames are skipped
|
||||
// --------------------------------------------------------------------
|
||||
float n_anim_frames = fabs(this.cur_fg_end_frame - this.cur_fg_start_frame);
|
||||
float time_per_frame = duration / n_anim_frames;
|
||||
// If faster than 10FPS, make thinks be called more often to not miss a frame callback
|
||||
if(time_per_frame < 0.10) {
|
||||
this.think_delta_time = time_per_frame * 0.5;
|
||||
}
|
||||
else {
|
||||
this.think_delta_time = 0.1;
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
};
|
||||
|
||||
void (framegroup fgroup) AI_Chase::set_framegroup = {
|
||||
// Increment framegroup counter. Reset every 100, we only use this to check when it has changed
|
||||
this.cur_fg_idx = (this.cur_fg_idx + 1) % 100;
|
||||
|
||||
// FIXME - frame callback isn't guaranteed to be called for every frame because sometimes we skip over frames
|
||||
// FIXME - I should modify the think delta time to run at 80% of the time between frames, or 0.10 seconds, whichever is greater.
|
||||
// FIXME - That way, if are playing an animation really fast, it'll call think more often
|
||||
this.cur_fg_start_frame = fgroup.start_frame;
|
||||
this.cur_fg_end_frame = fgroup.end_frame;
|
||||
this.cur_fg_frame_callback = fgroup.frame_callback;
|
||||
this.cur_fg_think_callback = fgroup.think_callback;
|
||||
this.set_framegroup_duration(fgroup.duration);
|
||||
|
||||
// Start the animation now
|
||||
this.cur_fg_frame_callback_is_start_frame = true;
|
||||
this.cur_fg_frame_callback_is_end_frame = false;
|
||||
this.frame = this.cur_fg_start_frame;
|
||||
this.cur_fg_start_time = time;
|
||||
this.cur_fg_frame_callback_next_frame = this.cur_fg_start_frame;
|
||||
// print("Done setting framegroup! Start frame: ");
|
||||
// print(ftos(fgroup.start_frame));
|
||||
// print(", End frame: ");
|
||||
// print(ftos(fgroup.end_frame));
|
||||
// print("\n");
|
||||
this.think_callback();
|
||||
};
|
||||
|
||||
|
||||
// Computes the length of a vector ignoring the Z-component
|
||||
float (vector ofs) vlen_xy = {
|
||||
return sqrt(ofs.x * ofs.x + ofs.y * ofs.y);
|
||||
}
|
||||
|
||||
|
||||
void (float dist) AI_Chase::do_walk_to_goal = {
|
||||
if(dist == 0) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void (float move_speed) AI_Chase::do_walk_to_goal = {
|
||||
if(move_speed == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -179,7 +117,7 @@ void (float dist) AI_Chase::do_walk_to_goal = {
|
|||
|
||||
// TOOD - If close, continue to next one...
|
||||
// TODO - Also make sure we're "close enough" in Z...
|
||||
if(vlen_xy(this.origin - goal_pos) < 20) {
|
||||
if(vlen_xy(this.origin - goal_pos) < 5) {
|
||||
print("Distance from target: ", ftos(vlen_xy(this.origin - goal_pos)), ", Cur point: ", ftos(this.pathfind_cur_point_idx), "\n");
|
||||
print("Current traversal: ", ftos(res->point_path_traversals[this.pathfind_cur_point_idx]),"\n");
|
||||
// If this point path is a traversal, teleport to traversal end spot
|
||||
|
@ -193,23 +131,21 @@ void (float dist) AI_Chase::do_walk_to_goal = {
|
|||
}
|
||||
}
|
||||
else {
|
||||
dist = 0;
|
||||
move_speed = 0;
|
||||
// TODO - Idle animation?
|
||||
}
|
||||
#endif // PC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this.ideal_yaw = vectoyaw(goal_pos - this.origin);
|
||||
ChangeYaw();
|
||||
vector new_velocity;
|
||||
float walk_dist = move_speed * this.think_delta_time;
|
||||
float dist_to_goal = vlen(goal_pos - this.origin);
|
||||
if(dist > dist_to_goal) {
|
||||
dist = dist_to_goal;
|
||||
if(walk_dist > dist_to_goal) {
|
||||
move_speed = dist_to_goal / this.think_delta_time;
|
||||
}
|
||||
new_velocity = normalize(goal_pos - this.origin) * dist;
|
||||
new_velocity = normalize(goal_pos - this.origin) * move_speed;
|
||||
new_velocity_z = this.velocity_z;
|
||||
this.velocity = new_velocity;
|
||||
};
|
||||
|
@ -225,28 +161,11 @@ void (float dist) AI_Chase::do_walk_to_goal = {
|
|||
|
||||
|
||||
|
||||
framegroup fg_zombie_walk_0;
|
||||
framegroup fg_zombie_walk_1;
|
||||
framegroup fg_zombie_walk_2;
|
||||
framegroup fg_zombie_jog_0;
|
||||
framegroup fg_zombie_run_0;
|
||||
// framegroup fg_zombie_run_1; // TODO - Either add new anims, or make new run FG with different speed?
|
||||
// framegroup fg_zombie_run_2; // TODO - Either add new anims, or make new run FG with different speed?
|
||||
framegroup fg_zombie_idle_0;
|
||||
framegroup fg_zombie_attack_0;
|
||||
framegroup fg_zombie_attack_1;
|
||||
framegroup fg_zombie_die_0;
|
||||
framegroup fg_zombie_die_1;
|
||||
framegroup fg_zombie_die_2;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
float get_zombie_walk_is_footstep(float frame) {
|
||||
frame = floor(frame);
|
||||
switch(frame) {
|
||||
switch(floor(frame)) {
|
||||
// ------------ Zombie Walk 1 --------------
|
||||
case 39: // Right foot
|
||||
case 44: // Left foot
|
||||
|
@ -259,49 +178,45 @@ float get_zombie_walk_is_footstep(float frame) {
|
|||
}
|
||||
|
||||
float get_zombie_walk_dist_for_frame(float frame) {
|
||||
frame = floor(frame);
|
||||
switch(frame) {
|
||||
switch(floor(frame)) {
|
||||
// ------------ Zombie Walk 1 --------------
|
||||
case 37:
|
||||
return 8;
|
||||
case 38:
|
||||
return 8;
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
return 3.5;
|
||||
case 43:
|
||||
return 8.8;
|
||||
return 3.5;
|
||||
case 44:
|
||||
return 9;
|
||||
return 8.8;
|
||||
case 45:
|
||||
return 9;
|
||||
case 46:
|
||||
return 4;
|
||||
case 47:
|
||||
return 7.8;
|
||||
return 4;
|
||||
case 48:
|
||||
return 5.2;
|
||||
return 7.8;
|
||||
case 49:
|
||||
return 2.4;
|
||||
return 5.2;
|
||||
case 50:
|
||||
return 2.8;
|
||||
return 2.4;
|
||||
case 51:
|
||||
return 6.5;
|
||||
return 2.8;
|
||||
case 52:
|
||||
return 6.5;
|
||||
case 53:
|
||||
return 7.7;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Called at the first frame of the current animation
|
||||
void zombie_walk_start_callback(entity ent) {
|
||||
// print("start called\n");
|
||||
};
|
||||
|
||||
|
||||
// Called once per animation frame:
|
||||
void zombie_walk_frame_callback(entity ent) {
|
||||
AI_Zombie zombie_ent = (AI_Zombie) ent;
|
||||
void zombie_walk_frame_callback() {
|
||||
AI_Zombie zombie_ent = (AI_Zombie) self;
|
||||
// print("frame called\n");
|
||||
// print("frame called. At frame: ");
|
||||
// print(ftos(ent.frame));
|
||||
|
@ -311,7 +226,7 @@ void zombie_walk_frame_callback(entity ent) {
|
|||
// // print(ftos(zombie_ent.cur_fg_frame_callback_is_end_frame));
|
||||
// print("\n");
|
||||
|
||||
if(get_zombie_walk_is_footstep(ent.frame)) {
|
||||
if(get_zombie_walk_is_footstep(zombie_ent.frame)) {
|
||||
if(random() < 0.5) {
|
||||
sound(self, 5, "sounds/zombie/s0.wav", 1, ATTN_NORM);
|
||||
}
|
||||
|
@ -320,72 +235,36 @@ void zombie_walk_frame_callback(entity ent) {
|
|||
}
|
||||
}
|
||||
|
||||
if(zombie_ent.cur_fg_frame_callback_is_end_frame) {
|
||||
// print("At final frame, restarting walk\n");
|
||||
zombie_ent.fg_walk();
|
||||
}
|
||||
|
||||
// TODO - If at final frame, call fg_walk again...
|
||||
// AI_Zombie zombie_ent = (AI_Zombie) ent;
|
||||
// zombie_ent.fg_walk();
|
||||
// ent.fg_walk();
|
||||
// Ideal animation velocity:
|
||||
// float dist_per_frame = get_zombie_walk_dist_for_frame(zombie_ent.frame);
|
||||
// float speed = dist_per_frame / zombie_ent.cur_anim_frametime;
|
||||
// // Convert that to velocity at think_time:
|
||||
// zombie_ent.do_walk_to_goal(speed);
|
||||
};
|
||||
|
||||
|
||||
// Called once per ent.think invocation
|
||||
void zombie_walk_think_callback(entity ent) {
|
||||
// print("Think called\n");
|
||||
void zombie_walk_think_callback() {
|
||||
print("Think called\n");
|
||||
// print("Think called for frame: ");
|
||||
// print(ftos(ent.frame));
|
||||
// print("\n");
|
||||
AI_Zombie zombie_ent = (AI_Zombie) ent;
|
||||
// zombie_ent.fg_walk();
|
||||
AI_Zombie zombie_ent = (AI_Zombie) self;
|
||||
|
||||
// "::classname" denotes the global ".string classname" field.
|
||||
entity player_ent = find( world, ::classname, "player");
|
||||
entity player_ent = find( world, classname, "player");
|
||||
if(player_ent != world) {
|
||||
zombie_ent.path_target = player_ent;
|
||||
ent.enemy = player_ent;
|
||||
zombie_ent.enemy = player_ent;
|
||||
}
|
||||
|
||||
|
||||
float n_anim_frames = fabs(zombie_ent.cur_fg_end_frame - zombie_ent.cur_fg_start_frame);
|
||||
// float dist_per_frame = 5.23125; // qu
|
||||
// // Ideal animation velocity:
|
||||
float dist_per_frame = get_zombie_walk_dist_for_frame(zombie_ent.frame);
|
||||
float time_per_frame = zombie_ent.cur_fg_duration / n_anim_frames;
|
||||
float speed = dist_per_frame / time_per_frame;
|
||||
float speed = dist_per_frame / zombie_ent.cur_anim_frametime;
|
||||
zombie_ent.do_walk_to_goal(speed);
|
||||
};
|
||||
|
||||
|
||||
void create_framegroups() {
|
||||
// walk0 37 52
|
||||
// walk1 53 66
|
||||
// walk3 67 82
|
||||
// jog0 116 129
|
||||
// run0 78 85
|
||||
// idle0 0 12
|
||||
// attack0 86 90
|
||||
// attack1 91 96
|
||||
// death0 123 133
|
||||
// death1 134 138
|
||||
// death2 139 148
|
||||
|
||||
// In blender, it's frames 38 to 53, inclusive
|
||||
init_framegroup( 38, 53, 1.0, zombie_walk_frame_callback, zombie_walk_think_callback, fg_zombie_walk_0);
|
||||
init_framegroup( 53, 66, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_walk_1);
|
||||
init_framegroup( 67, 82, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_walk_2);
|
||||
init_framegroup( 116, 129, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_jog_0);
|
||||
init_framegroup( 78, 85, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_run_0);
|
||||
init_framegroup( 0, 12, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_idle_0);
|
||||
init_framegroup( 86, 90, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_attack_0);
|
||||
init_framegroup( 91, 96, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_attack_1);
|
||||
init_framegroup( 123, 133, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_die_0);
|
||||
init_framegroup( 134, 138, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_die_1);
|
||||
init_framegroup( 139, 148, 10.0, (void(entity)) SUB_Null, (void(entity)) SUB_Null, fg_zombie_die_2);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -427,7 +306,7 @@ void(vector org) AI_Zombie::init = {
|
|||
// ---------------------------------
|
||||
this.think_delta_time = 0.1; // 10x per second
|
||||
this.nextthink = time + this.think_delta_time;
|
||||
this.cur_fg_start_time = -1;
|
||||
// this.cur_fg_start_time = -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -437,116 +316,93 @@ void(vector org) AI_Zombie::init = {
|
|||
// }
|
||||
|
||||
|
||||
void () AI_Zombie::fg_walk = {
|
||||
this.set_framegroup(fg_zombie_walk_0);
|
||||
this.set_framegroup_duration(fg_zombie_walk_0.duration * (1.0 + 3.0 * random()));
|
||||
// print("Set anim duration to: ");
|
||||
// print(ftos(this.cur_fg_duration));
|
||||
// print("\n");
|
||||
}
|
||||
void () AI_Zombie::fg_die = {
|
||||
// TODO - Execute -- zombie_die_0
|
||||
}
|
||||
void () AI_Zombie::fg_attack = {
|
||||
// TODO - Execute an attack framegroup
|
||||
}
|
||||
void () AI_Zombie::fg_idle = {
|
||||
// TODO - Execute the idle framegroup
|
||||
}
|
||||
|
||||
|
||||
// void () AI_Zombie::traverse = {
|
||||
// this.traversal_idx; // Can't use pointers... but can use index!
|
||||
// this.traversal_state;
|
||||
// this.traversal_substate;
|
||||
|
||||
// // TODO - Check traversal type, check if this class knows how to perform it.
|
||||
|
||||
// float traversal_idx = 0;
|
||||
// // TODO - Once we know traversal type, the AI_Zombie class will know which think_callback to use
|
||||
// // TODO - Set up a test scene on the map, set up a test traversal, have dummy zombie play the test traversal
|
||||
|
||||
|
||||
// this.traversal_callback = zombie_traversal_hop_barricade_think;
|
||||
// void (entity ent) zombie_hop_barricade_traveral_think = {
|
||||
// AI_Zombie zombie_ent = (AI_Zombie) ent;
|
||||
// // TODO - need to initialize traversal state and traversal substate
|
||||
// // Initialize state
|
||||
// if(ent.traversal_state < 0) {
|
||||
// ent.traversal_state = 0;
|
||||
// ent.traversal_substate = 0;
|
||||
// }
|
||||
|
||||
// // State 0 -- Start hopping, start playing anim, lerp towards
|
||||
// // TODO - How to adjust animation speed scale?
|
||||
// // TODO - How best to control animation from here?
|
||||
// if(ent.traversal_state == 0) {
|
||||
// // TODO - Somehow start playing animation?
|
||||
|
||||
// }
|
||||
// // ...
|
||||
// // On final state, clear traversal
|
||||
// else {
|
||||
// ent.traversal_state = -1;
|
||||
// // TODO - Revert to zombie original behavior, fg_walk?
|
||||
// zombie_ent.fg_walk();
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
// // TODO - Implement think logic for hop barricade traversal
|
||||
// // Each traversal has a different think function implementation...
|
||||
// // When I call zombie.traverse(), I need some way of telling the zombie which barricade to traverse
|
||||
// // Maybe traverse has a traversal_idx as its argument?
|
||||
// // zombie_ent.traverse(traversal_idx);
|
||||
|
||||
// // That tells the zombie to perform this traversal
|
||||
// // And the traversal think function will be stored in the struct
|
||||
|
||||
|
||||
|
||||
// #define MYFUNC(DUMMY, FN, I) int FN(void) { return I; }
|
||||
// #define GENFUNCS(...) \
|
||||
// P99_FOR(, P99_NARG(__VA_ARGS__), P00_IGN, MYFUNC, __VA_ARGS__) \
|
||||
// int (*function_table)(void)[] = { __VA_ARGS__ }
|
||||
|
||||
// GENFUNCS(toto, hui, gogo);
|
||||
|
||||
|
||||
void() test_frame_callback = {
|
||||
// print("Frame Callback: ", self.classname, "\n");
|
||||
AI_Zombie ent = self;
|
||||
print("Frame Callback. Frame: ", ftos(ent.frame), " anim frame_idx: ", ftos(ent.cur_anim_frame_idx), "\n");
|
||||
}
|
||||
|
||||
void() test_new_ent = {
|
||||
create_framegroups();
|
||||
|
||||
makevectors(self.v_angle);
|
||||
// AI_Chase test_ent = spawn(AI_Chase);
|
||||
AI_Zombie zombie = spawn(AI_Zombie);
|
||||
zombie.init(self.origin + v_forward * 100);
|
||||
zombie.fg_walk();
|
||||
// TODO - If riser, Immediately set frmae to below ground frame
|
||||
zombie.frame = get_anim_frame_zombie_rise(0);
|
||||
zombie.play_anim(get_anim_frame_zombie_rise, get_anim_length_zombie_rise(), ANIM_STOP_TYPE_NEXT_ANIM);
|
||||
zombie.queue_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
||||
zombie.frame_callback = zombie_walk_frame_callback;
|
||||
zombie.think_callback = zombie_walk_think_callback;
|
||||
|
||||
|
||||
// zombie.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_NEXT_ANIM);
|
||||
// zombie.queue_anim(get_anim_frame_zombie_rise, get_anim_length_zombie_rise(), ANIM_STOP_TYPE_LOOP);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// somefunc();
|
||||
// framegroup_registry zombie_th_reg;
|
||||
// // framegroup_registry crawler_th_reg;
|
||||
// // framegroup_registry dog_th_reg;
|
||||
|
||||
// framegroup zombie_attack_0;
|
||||
// // framegroup zombie_attack_1;
|
||||
// // framegroup zombie_idle_0;
|
||||
// // framegroup zombie_die_0;
|
||||
// // framegroup zombie_die_1;
|
||||
// // framegroup zombie_die_2;
|
||||
// // framegroup zombie_walk_0;
|
||||
// // framegroup zombie_walk_1;
|
||||
// // framegroup zombie_walk_2;
|
||||
// // framegroup zombie_jog_0;
|
||||
// // framegroup zombie_run_1;
|
||||
// // framegroup zombie_run_2;
|
||||
// // framegroup zombie_run_3;
|
||||
|
||||
|
||||
|
||||
// create_framegroup( zombie_attack_0, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_attack_1, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_idle_0, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_die_0, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_die_1, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_die_2, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_walk_0, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_walk_1, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_walk_2, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_jog_0, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_run_1, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_run_2, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
// // create_framegroup( zombie_run_3, 0, 10, 5.0, SUB_Null, SUB_Null, SUB_Null);
|
||||
|
||||
|
||||
// // zombie_th_reg.fg_attack.num_framegroups = 2;
|
||||
|
||||
// print(strcat("Num before:",ftos(zombie_th_reg.fg_attack.num_framegroups),"\n"));
|
||||
// register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num after:",ftos(zombie_th_reg.fg_attack.num_framegroups),"\n"));
|
||||
|
||||
|
||||
|
||||
// zombie_th_reg.fg_attack = register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num before:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// zombie_th_reg.fg_attack = register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num after:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// print(strcat("Num before:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// zombie_th_reg.fg_attack = register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num after:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// print(strcat("Num before:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// zombie_th_reg.fg_attack = register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num after:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// print(strcat("Num before:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// zombie_th_reg.fg_attack = register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num after:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// print(strcat("Num before:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// zombie_th_reg.fg_attack = register_framegroup( zombie_th_reg.fg_attack, zombie_attack_0);
|
||||
// print(strcat("Num after:",ftos(zombie_th_reg.fg_attack.num_framegroups)));
|
||||
// print(ftos(result));
|
||||
// print("\n");
|
||||
// result = register_framegroup( &(zombie_th_reg.fg_attack), &zombie_attack_1);
|
||||
// print(ftos(result));
|
||||
// print("\n");
|
||||
// result = register_framegroup( &(zombie_th_reg.fg_idle), &zombie_idle_0);
|
||||
// print(ftos(result));
|
||||
// print("\n");
|
||||
// result = register_framegroup( &(zombie_th_reg.fg_die), &zombie_die_0);
|
||||
// print(ftos(result));
|
||||
// print("\n");
|
||||
// result = register_framegroup( &(zombie_th_reg.fg_die), &zombie_die_1);
|
||||
// print(ftos(result));
|
||||
// print("\n");
|
||||
// TODO - Set frametime to something random?
|
||||
zombie.cur_anim_frametime = 0.1;
|
||||
// zombie.next_anim_frametime = 0.05 + 0.1 * random();
|
||||
zombie.next_anim_frametime = 0.13;
|
||||
// zombie.next_anim_frametime = 0.1;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -80,15 +80,14 @@ void sv_load_navmesh_data() {
|
|||
return;
|
||||
}
|
||||
|
||||
//First line contains navmesh file semver
|
||||
// First line contains navmesh file semver
|
||||
string nav_file_version = fgets(file);
|
||||
|
||||
//Next line contains vertex count
|
||||
string line = fgets(file);
|
||||
float vert_count = stof(line);
|
||||
// Next line contains vertex count
|
||||
float vert_count = stof(fgets(file));
|
||||
|
||||
if(vert_count > sv_navmesh_verts.length) {
|
||||
print("Error: navmesh file \"",filepath,"\" has an invalid vert count. (" , line, " > ", ftos(sv_navmesh_verts.length),").\n");
|
||||
print("Error: navmesh file \"",filepath,"\" has an invalid vert count. (" , vert_count, " > ", ftos(sv_navmesh_verts.length),").\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
@ -96,21 +95,15 @@ void sv_load_navmesh_data() {
|
|||
//The navmesh appears to be valid (we shouldn't need to clear the current navmesh values)
|
||||
sv_navmesh_vert_count = vert_count;
|
||||
|
||||
//Temp vector to assign component-wise
|
||||
vector temp;
|
||||
|
||||
|
||||
//Reading all of the vertex positions
|
||||
for(float i = 0; i < sv_navmesh_vert_count; i++) {
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
sv_navmesh_verts[i].pos.x = temp.x;
|
||||
sv_navmesh_verts[i].pos.y = temp.y;
|
||||
sv_navmesh_verts[i].pos.z = temp.z;
|
||||
sv_navmesh_verts[i].pos = stov(fgets(file));
|
||||
}
|
||||
|
||||
//Next line contains the number of polygons
|
||||
sv_navmesh_poly_count = stof(fgets(file));
|
||||
print("Polygon count: ", ftos(sv_navmesh_poly_count), "\n");
|
||||
|
||||
//The next lines are each polygon
|
||||
for(float i = 0; i < sv_navmesh_poly_count; i++) {
|
||||
|
@ -122,10 +115,7 @@ void sv_load_navmesh_data() {
|
|||
sv_navmesh_polies[i].verts[2] = stof(fgets(file));
|
||||
sv_navmesh_polies[i].verts[3] = stof(fgets(file));
|
||||
// Get polygon center
|
||||
temp = stov(fgets(file));
|
||||
sv_navmesh_polies[i].center.x = temp.x;
|
||||
sv_navmesh_polies[i].center.y = temp.y;
|
||||
sv_navmesh_polies[i].center.z = temp.z;
|
||||
sv_navmesh_polies[i].center = stov(fgets(file));
|
||||
// Get link count
|
||||
sv_navmesh_polies[i].connected_polies_count = stof(fgets(file));
|
||||
// Get links
|
||||
|
@ -151,7 +141,7 @@ void sv_load_navmesh_data() {
|
|||
|
||||
// If navmesh file version 0.0.0, no traversals
|
||||
// FIXME - Need a better way to do this..
|
||||
if(strcmp(nav_file_version, "0.0.0") != 0) {
|
||||
if(nav_file_version != "0.0.0") {
|
||||
// Get connected traversals
|
||||
sv_navmesh_polies[i].connected_traversals_count = stof(fgets(file));
|
||||
for(float j = 0; j < sv_navmesh_polies[i].connected_traversals_count; j++) {
|
||||
|
@ -160,8 +150,11 @@ void sv_load_navmesh_data() {
|
|||
}
|
||||
//Get polygon doortarget
|
||||
sv_navmesh_polies[i].doortarget = fgets(file);
|
||||
//Get entrance edge
|
||||
sv_navmesh_polies[i].entrance_edge = stoi(fgets(file));
|
||||
// If v0.0.0, throw away entrance edge (legacy feature not supported)
|
||||
if(nav_file_version == "0.0.0") {
|
||||
// sv_navmesh_polies[i].entrance_edge = stoi(fgets(file));
|
||||
fgets(file);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -169,27 +162,15 @@ void sv_load_navmesh_data() {
|
|||
// -----------------------------------------------------------------------
|
||||
// If navmesh file version 0.0.0, no traversals
|
||||
// FIXME - Need a better way to do this..
|
||||
if(strcmp(nav_file_version, "0.0.0") != 0) {
|
||||
if(nav_file_version != "0.0.0") {
|
||||
//Next line contains the number of traverals
|
||||
sv_navmesh_traversal_count = stof(fgets(file));
|
||||
|
||||
//The next lines are each traversal
|
||||
for(float i = 0; i < sv_navmesh_traversal_count; i++) {
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
sv_navmesh_traversals[i].start_pos.x = temp.x;
|
||||
sv_navmesh_traversals[i].start_pos.y = temp.y;
|
||||
sv_navmesh_traversals[i].start_pos.z = temp.z;
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
sv_navmesh_traversals[i].midpoint_pos.x = temp.x;
|
||||
sv_navmesh_traversals[i].midpoint_pos.y = temp.y;
|
||||
sv_navmesh_traversals[i].midpoint_pos.z = temp.z;
|
||||
line = fgets(file);
|
||||
temp = stov(line);
|
||||
sv_navmesh_traversals[i].end_pos.x = temp.x;
|
||||
sv_navmesh_traversals[i].end_pos.y = temp.y;
|
||||
sv_navmesh_traversals[i].end_pos.z = temp.z;
|
||||
sv_navmesh_traversals[i].start_pos = stov(fgets(file));
|
||||
sv_navmesh_traversals[i].midpoint_pos = stov(fgets(file));
|
||||
sv_navmesh_traversals[i].end_pos = stov(fgets(file));
|
||||
sv_navmesh_traversals[i].angle = stof(fgets(file));
|
||||
sv_navmesh_traversals[i].use_midpoint = stof(fgets(file));
|
||||
sv_navmesh_traversals[i].end_poly = stof(fgets(file));
|
||||
|
@ -272,22 +253,19 @@ float sv_navmesh_dist_to_poly(vector pos, float poly_index)
|
|||
//Returns polygon that pos is inside of.
|
||||
//If we are in no polygon, returns a polygon whose edge we are sufficiently close to (might be in but are not due to a small error)
|
||||
//Otherwise, returns -1
|
||||
float sv_navmesh_get_containing_poly(vector pos)
|
||||
{
|
||||
float sv_navmesh_get_containing_poly(vector pos) {
|
||||
//Get nearest polygon, and check if pos is in that polygon
|
||||
float closest_poly = -1;
|
||||
float closest_poly_dist = 1000000;
|
||||
|
||||
//In reality, there's no need to try ALL polygons, the one we are in should be within the nearest 10 or so, but checking all to be safe
|
||||
for(float i = 0; i < sv_navmesh_poly_count; i++)
|
||||
{
|
||||
for(float i = 0; i < sv_navmesh_poly_count; i++) {
|
||||
//Check if we are sufficiently close enough to polygon i in the z-axis
|
||||
//Current method of checking: if pos is within 30 qu of polygon z-axis bounds
|
||||
float poly_min_z = sv_navmesh_verts[sv_navmesh_polies[i].verts[0]].pos.z;
|
||||
float poly_max_z = poly_min_z;
|
||||
|
||||
for(float j = 0; j < sv_navmesh_polies[i].vert_count; j++)
|
||||
{
|
||||
for(float j = 0; j < sv_navmesh_polies[i].vert_count; j++) {
|
||||
float vert_z = sv_navmesh_verts[sv_navmesh_polies[i].verts[j]].pos.z;
|
||||
poly_min_z = min(poly_min_z, vert_z);
|
||||
poly_max_z = max(poly_max_z, vert_z);
|
||||
|
@ -295,15 +273,12 @@ float sv_navmesh_get_containing_poly(vector pos)
|
|||
|
||||
// If we NOT between [min - 30, max + 30], skip this polygon
|
||||
// if(fabs(sv_navmesh_polies[0].center.z - pos.z) >= 30)
|
||||
if(pos.z < poly_min_z - 30 || pos.z > poly_max_z + 30)
|
||||
{
|
||||
if(pos.z < poly_min_z - 30 || pos.z > poly_max_z + 30) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//Check if we are in polygon i
|
||||
if(sv_navmesh_is_inside_poly(pos,i))
|
||||
{
|
||||
if(sv_navmesh_is_inside_poly(pos,i)) {
|
||||
// NOTE - Because is_inside_poly only checks if we are in it on X & Y axes,
|
||||
// NOTE we may have found a polygon on a floor below us or above us.
|
||||
// NOTE However, this may not be an issue. A polygon on a floor below
|
||||
|
@ -317,25 +292,17 @@ float sv_navmesh_get_containing_poly(vector pos)
|
|||
|
||||
//If we are not in polygon i, check if we arse very close to one of its edges
|
||||
float dist = sv_navmesh_dist_to_poly(pos,i);
|
||||
|
||||
if(dist >= 0)
|
||||
{
|
||||
if(dist < closest_poly_dist)
|
||||
{
|
||||
closest_poly = i;
|
||||
closest_poly_dist = dist;
|
||||
}
|
||||
if(dist >= 0 && dist < closest_poly_dist) {
|
||||
closest_poly = i;
|
||||
closest_poly_dist = dist;
|
||||
}
|
||||
|
||||
}
|
||||
//============================================
|
||||
|
||||
/*if(closest_poly == -1)
|
||||
{
|
||||
/*if(closest_poly == -1) {
|
||||
print("Ent pos is not in or near any polygons.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
print("Ent pos is near but not in poly: closest_poly.\n");
|
||||
}*/
|
||||
|
||||
|
|
|
@ -971,11 +971,22 @@ float sv_navmesh_pathfind_start(float start_poly, float goal_poly, vector start_
|
|||
// print(ftos(neighbor_poly));
|
||||
// print(".\n");
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Door check
|
||||
// ----------------------------------------------------------------
|
||||
// NOTE - If polygon's door hasn't been opened, don't consider it.
|
||||
// NOTE - This check isn't done in the navmesh editor.
|
||||
// If this polygon references a door:
|
||||
if(sv_navmesh_polies[neighbor_poly].doortarget != "") {
|
||||
entity door;
|
||||
door = find(world, wayTarget, sv_navmesh_polies[neighbor_poly].doortarget);
|
||||
if(door != world) {
|
||||
// If the referenced door is closed, don't consider this polygon.
|
||||
if(door.state == STATE_BOTTOM) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -485,20 +485,7 @@ navmesh_pathfind_result *sv_zombie_pathfind_result_aux; // Used as secondary, so
|
|||
|
||||
//=================================================================
|
||||
//========================== AI defs ==============================
|
||||
var struct framegroup {
|
||||
float start_frame;
|
||||
float end_frame;
|
||||
float duration;
|
||||
// void(entity) start_callback; // Called at the first frame of the range
|
||||
void(entity) frame_callback; // Called at every frame of the range (after start / finish callbacks)
|
||||
// void(entity) end_callback; // Called at the last frame of the range
|
||||
// FIXME - Increasing the size of this framegroup by one more function pointer causes chaos...
|
||||
// I assume I run out of space to pass framegroups along as arguments at any point...
|
||||
// It starts to write into weird memory locations, like overriding self / world... things just break down.
|
||||
// TODO - How can I refactor this to work?
|
||||
void(entity) think_callback; // Called at each think invocation
|
||||
// -- Maybe I can get rid of start / end callbacks? idk
|
||||
// I should think about how I actually plan on using these...
|
||||
|
||||
|
||||
// -----------–-----------–-----------–-----------–-----------–-----------–----
|
||||
// Animation Definitions
|
||||
|
@ -535,54 +522,110 @@ var struct framegroup {
|
|||
float get_anim_length_##ANIM_NAME## () {float frames[] = {__VA_ARGS__}; return frames.length;};
|
||||
// -----------–-----------–-----------–-----------–-----------–-----------–----
|
||||
|
||||
// TODO - Get rid of start / end callback, add fields to the AI_Chase class that denotes
|
||||
// TODO - These callbacks will be executed at the same time as frame anyways.
|
||||
enum anim_stop_type:float {
|
||||
ANIM_STOP_TYPE_STOP, // Animation stops and freezes at final frame.
|
||||
ANIM_STOP_TYPE_LOOP, // Animation starts again from the first frame.
|
||||
ANIM_STOP_TYPE_NEXT_ANIM, // Another animation is played when this one finishes.
|
||||
};
|
||||
|
||||
|
||||
class AI_Chase : entity {
|
||||
// framegroup_registry *th_reg;
|
||||
entity path_target; // If specified, path towards entity
|
||||
vector path_pos; // Otherwise, path towards location specified
|
||||
float think_delta_time; // Delta time (seconds) between each `this.think();`
|
||||
|
||||
|
||||
// Regardless of what animation we're playing (or not playing), we have a think callback
|
||||
virtual void() think_callback = SUB_Null;
|
||||
// We also have a frame callback that's called each time we reach a new animation frame.
|
||||
virtual void() frame_callback = SUB_Null;
|
||||
|
||||
// ------------------------------
|
||||
// Current Framegroup value vars
|
||||
// Animation variables
|
||||
// ------------------------------
|
||||
float cur_fg_start_time;
|
||||
float cur_fg_start_frame;
|
||||
float cur_fg_end_frame;
|
||||
float cur_fg_duration;
|
||||
// void() endanimfunc = SUB_Null;
|
||||
// virtual void(entity) cur_fg_start_callback = SUB_Null;
|
||||
virtual void(entity) cur_fg_frame_callback = (void(entity)) SUB_Null;
|
||||
// virtual void(entity) cur_fg_end_callback = SUB_Null;
|
||||
virtual void(entity) cur_fg_think_callback = (void(entity)) SUB_Null;
|
||||
// ------------------------------
|
||||
// Framegroup state vars
|
||||
// ------------------------------
|
||||
float cur_fg_idx; // Counter for checking when the framegroup has been changed
|
||||
float cur_fg_frame_callback_next_frame;
|
||||
float cur_fg_frame_callback_is_start_frame; // Is set to true when performing cur_fg_frame_callback for the first framegroup frame
|
||||
float cur_fg_frame_callback_is_end_frame; // Is set to true when performing cur_fg_frame_callback for the final framegroup frame
|
||||
// --- Current animation vars ---
|
||||
virtual float(float) cur_anim_get_frame_func = (float(float)) SUB_Null; // Gets frame number from frame index. Assign to `get_anim_frame_{ANIM_NAME}`, as generated by DEFINE_ANIM
|
||||
float cur_anim_length; // The length of the current animation. Assign to `get_anim_length_{ANIM_NAME}()`, as generated by DEFINE_ANIM)
|
||||
float cur_anim_frametime; // Time (in seconds) between frames, 0.1 for 10FPS
|
||||
anim_stop_type cur_anim_stop_type; // ANIM_STOP_TYPE_STOP, ANIM_STOP_TYPE_LOOP, or ANIM_STOP_TYPE_NEXT_ANIM
|
||||
// --- Next / Queued animation vars ---
|
||||
virtual float(float) next_anim_get_frame_func = (float(float)) SUB_Null; // Gets frame number from frame index. Assign to `get_anim_frame_{ANIM_NAME}`, as generated by DEFINE_ANIM
|
||||
float next_anim_length; // The length of the current animation. Assign to `get_anim_length_{ANIM_NAME}()`, as generated by DEFINE_ANIM)
|
||||
float next_anim_frametime; // Time (in seconds) between frames, 0.1 for 10FPS
|
||||
anim_stop_type next_anim_stop_type; // ANIM_STOP_TYPE_STOP or ANIM_STOP_TYPE_LOOP
|
||||
// --- Current animation state vars ---
|
||||
float cur_anim_start_time;
|
||||
float cur_anim_frame_idx; // Counter from 0 to `cur_anim_n_frames`
|
||||
// ------------------------------
|
||||
|
||||
|
||||
float pathfind_result_idx; // TODO - Need to increment this on instantiation
|
||||
float pathfind_cur_point_idx;
|
||||
|
||||
|
||||
// Constructor. Called when calling `spawn(AI_Chase);`
|
||||
virtual void() AI_Chase;
|
||||
|
||||
|
||||
virtual void() think;
|
||||
virtual void (float duration) set_framegroup_duration;
|
||||
virtual void (framegroup fgroup) set_framegroup;
|
||||
|
||||
|
||||
virtual void () fg_die = {};
|
||||
virtual void () fg_walk = {};
|
||||
virtual void () fg_attack = {};
|
||||
virtual void () fg_idle = {};
|
||||
// Stop what you're doing and play this animation immediately.
|
||||
virtual void(float(float) anim_frame_func, float anim_length, anim_stop_type stop_type) play_anim = {
|
||||
// Assign Animation Vars
|
||||
this.cur_anim_get_frame_func = anim_frame_func;
|
||||
this.cur_anim_length = anim_length;
|
||||
this.cur_anim_stop_type = stop_type;
|
||||
this.cur_anim_frametime = 0.1; // TODO - Make this a param?
|
||||
this.cur_anim_frametime = 0.2; // TODO - Make this a param?
|
||||
|
||||
// Reset Animation state Vars
|
||||
this.cur_anim_start_time = time;
|
||||
this.cur_anim_frame_idx = 0;
|
||||
|
||||
// Adjust think_delta_time if needed
|
||||
// If we want to play the animation faster than 10FPS, call logic ticks faster so the animation will be played
|
||||
if(this.cur_anim_frametime < 0.10) {
|
||||
this.think_delta_time = this.cur_anim_frametime * 0.5;
|
||||
}
|
||||
else {
|
||||
this.think_delta_time = 0.1;
|
||||
}
|
||||
this.think_delta_time = this.cur_anim_frametime * 0.5;
|
||||
this.think_delta_time = this.cur_anim_frametime * 0.1;
|
||||
|
||||
|
||||
|
||||
// TODO - Do some math and figure out if we need to
|
||||
// TODO - Thinktime should be adjusted so that
|
||||
// TOOD - this.thinktime = min(0.1, this.cur_anim_frametime * 0.05);
|
||||
|
||||
// TODO - Reset FPS to 10 FPS, (frametime = 0.1)
|
||||
// TODO - Add a function that allows this to play slower or faster?
|
||||
};
|
||||
|
||||
// Queue up another animation to play when the current one finishes
|
||||
virtual void(float(float) anim_frame_func, float anim_length, anim_stop_type stop_type) queue_anim {
|
||||
// This isn't allowed, we can't queue more than one animation.
|
||||
// Queued animation stop type must be: ANIM_STOP_TYPE_STOP, or ANIM_STOP_TYPE_LOOP
|
||||
if(stop_type == ANIM_STOP_TYPE_NEXT_ANIM) {
|
||||
return;
|
||||
}
|
||||
// Indicate that we have a next animation queued up the next time the current animation finishes.
|
||||
this.cur_anim_stop_type = ANIM_STOP_TYPE_NEXT_ANIM;
|
||||
|
||||
this.next_anim_get_frame_func = anim_frame_func;
|
||||
this.next_anim_length = anim_length;
|
||||
this.next_anim_stop_type = stop_type;
|
||||
this.next_anim_frametime = 0.1;
|
||||
this.next_anim_frametime = 0.2; // FIXME - Parameterize this?
|
||||
};
|
||||
|
||||
|
||||
|
||||
// virtual void () fg_die = {};
|
||||
// virtual void () fg_walk = {};
|
||||
// virtual void () fg_attack = {};
|
||||
// virtual void () fg_idle = {};
|
||||
|
||||
virtual void (float dist) do_walk_to_goal;
|
||||
};
|
||||
|
@ -596,12 +639,21 @@ class AI_Zombie : AI_Chase {
|
|||
// This should be called explicitly:
|
||||
virtual void(vector org) init;
|
||||
|
||||
virtual void () fg_die;
|
||||
virtual void () fg_walk;
|
||||
virtual void () fg_attack;
|
||||
virtual void () fg_idle;
|
||||
// virtual void () fg_die;
|
||||
// virtual void () fg_walk;
|
||||
// virtual void () fg_attack;
|
||||
// virtual void () fg_idle;
|
||||
|
||||
// static void () setup_frames = {
|
||||
// // this.zombie_idle_frames = {1,2,3,4,5,6,7,8,9,10,11,12,13};
|
||||
// // this.cur_frames = zombie_idle_frames;
|
||||
// // FIXME - I can't figure out a way to assign an array...
|
||||
// // Even if I convert an animation to a struct, I can't do arbitrary-length arrays...
|
||||
// // I also can't fill them in in this convenient syntax... it's ridiculous.
|
||||
// };
|
||||
};
|
||||
|
||||
// AI_Zombie.zombie_idle_frames = {1,2,3,4,5,6,7,8,9,10,11,12,13};
|
||||
|
||||
//=================================================================
|
||||
|
||||
|
|
|
@ -348,7 +348,8 @@ void() door_trigger_touch =
|
|||
|
||||
#ifdef PC
|
||||
if(cvar("navmesh_edit_mode")) {
|
||||
if(strcmp(cvar_string("nav_editor_active_door"), self.owner.wayTarget) != 0) {
|
||||
// if(strcmp(cvar_string("nav_editor_active_door"), self.owner.wayTarget) != 0) {
|
||||
if(cvar_string("nav_editor_active_door") != self.owner.wayTarget) {
|
||||
bprint(PRINT_HIGH, "Current Door for navmesh editor set to \"");
|
||||
bprint(PRINT_HIGH, self.owner.wayTarget); // naiveil (FIXME)
|
||||
bprint(PRINT_HIGH, "\"\n");
|
||||
|
|
|
@ -107,6 +107,23 @@ float(float a, float b, float mix) unclamped_lerp =
|
|||
return (b * mix + a * ( 1 - mix ) );
|
||||
}
|
||||
|
||||
#ifndef PC // FTE has built-ins for min / max
|
||||
float(float a, float b) min =
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
float(float a, float b) max =
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
#endif // PC
|
||||
|
||||
// Computes the length of a vector ignoring the Z-component
|
||||
float (vector ofs) vlen_xy = {
|
||||
return vlen([ofs.x, ofs.y, 0]);
|
||||
}
|
||||
|
||||
|
||||
vector(vector a, vector b, float mix) lerpVector =
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ struct navmesh_poly {
|
|||
float vert_count;
|
||||
string doortarget; // "" or matches the .wayTarget field of a door entity. Polygon is only used when door is open (i.e. door.state == STATE_BOTTOM)
|
||||
// TODO - Remove this, will be replaced by traversals
|
||||
int entrance_edge; // If != -1, specifies which edge index this polygon can be entered from. (0,1,2, or 3)
|
||||
// int entrance_edge; // If != -1, specifies which edge index this polygon can be entered from. (0,1,2, or 3)
|
||||
|
||||
float connected_traversals_count; // How many traversals start in this polygon
|
||||
float connected_traversals[NAV_MAX_POLY_TRAVERSALS]; // List of traversals that start in this polygon
|
||||
|
|
Loading…
Reference in a new issue