mirror of
https://github.com/nzp-team/quakec.git
synced 2024-11-22 11:51:11 +00:00
CLIENT: Add FTE skel defs
SERVER: Add test IQM ledge-climb traversal
This commit is contained in:
parent
e3dcb2aa13
commit
11004c96b5
3 changed files with 688 additions and 629 deletions
|
@ -1179,10 +1179,28 @@ float(float modlindex, optional float useabstransforms) skel_create = #263; /* P
|
||||||
Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model.
|
Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model.
|
||||||
eg: self.skeletonobject = skel_create(self.modelindex); */
|
eg: self.skeletonobject = skel_create(self.modelindex); */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int sourcemodelindex; /*frame data will be imported from this model, bones must be compatible*/
|
||||||
|
int reserved;
|
||||||
|
int firstbone;
|
||||||
|
int lastbone;
|
||||||
|
float prescale; /*0 destroys existing data, 1 retains it*/
|
||||||
|
float scale[4]; /*you'll need to do lerpfrac manually*/
|
||||||
|
int animation[4];
|
||||||
|
float animationtime[4];
|
||||||
|
/*halflife models*/
|
||||||
|
float subblend[2];
|
||||||
|
float controllers[5];
|
||||||
|
} skelblend_t;
|
||||||
|
|
||||||
float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS
|
float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addfrac) skel_build = #264; /* Part of FTE_CSQC_SKELETONOBJECTS
|
||||||
Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object.
|
Animation data (according to the entity's frame info) is pulled from the specified model and blended into the specified skeletal object.
|
||||||
If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */
|
If retainfrac is set to 0 on the first call and 1 on the others, you can blend multiple animations together according to the addfrac value. The final weight should be 1. Other values will result in scaling and/or other weirdness. You can use firstbone and lastbone to update only part of the skeletal object, to allow legs to animate separately from torso, use 0 for both arguments to specify all, as bones are 1-based. */
|
||||||
|
|
||||||
|
float(float skel, int numblends, skelblend_t *weights, int structsize) skel_build_ptr = #0:skel_build_ptr; /*
|
||||||
|
Like skel_build, but slightly simpler. */
|
||||||
|
|
||||||
|
|
||||||
float(float skel) skel_get_numbones = #265; /* Part of FTE_CSQC_SKELETONOBJECTS
|
float(float skel) skel_get_numbones = #265; /* Part of FTE_CSQC_SKELETONOBJECTS
|
||||||
Retrives the number of bones in the model. The valid range is 1<=bone<=numbones. */
|
Retrives the number of bones in the model. The valid range is 1<=bone<=numbones. */
|
||||||
|
|
||||||
|
@ -1627,6 +1645,10 @@ void(entity e, string skinfilename, optional string skindata) setcustomskin = #3
|
||||||
The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.
|
The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.
|
||||||
Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). */
|
Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader). */
|
||||||
|
|
||||||
|
float(string skinfilename, optional string skindata) loadcustomskin = #377;
|
||||||
|
void(entity e, float skinobj) applycustomskin = #378;
|
||||||
|
void(float skinobj) releasecustomskin = #379;
|
||||||
|
|
||||||
__variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC
|
__variant*(int size) memalloc = #384; /* Part of FTE_MEMALLOC
|
||||||
Allocate an arbitary block of memory */
|
Allocate an arbitary block of memory */
|
||||||
|
|
||||||
|
|
|
@ -509,10 +509,6 @@ float() zombie_predraw = {
|
||||||
|
|
||||||
// Due to QC's limit of 8-args per vararg func, split this up into
|
// Due to QC's limit of 8-args per vararg func, split this up into
|
||||||
// a few different sprintf calls.
|
// a few different sprintf calls.
|
||||||
string skin_str = "";
|
|
||||||
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_BODY, )
|
|
||||||
|
|
||||||
|
|
||||||
string skin_str = "";
|
string skin_str = "";
|
||||||
// Add in the geomset defs
|
// Add in the geomset defs
|
||||||
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_BODY, 0);
|
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_BODY, 0);
|
||||||
|
@ -522,7 +518,7 @@ float() zombie_predraw = {
|
||||||
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_LEG_L, self.limbs_state & ZOMBIE_LIMB_STATE_LEG_L == 0);
|
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_LEG_L, self.limbs_state & ZOMBIE_LIMB_STATE_LEG_L == 0);
|
||||||
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_LEG_R, self.limbs_state & ZOMBIE_LIMB_STATE_LEG_R == 0);
|
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_LEG_R, self.limbs_state & ZOMBIE_LIMB_STATE_LEG_R == 0);
|
||||||
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_ARM_R, self.limbs_state & ZOMBIE_LIMB_STATE_ARM_R == 0);
|
skin_str = sprintf("%sgeomset %d %d\n", skin_str, ZOMBIE_IQM_GEOMSET_ARM_R, self.limbs_state & ZOMBIE_LIMB_STATE_ARM_R == 0);
|
||||||
// Add in the shader defs
|
// Add in the per-mesh shader defs
|
||||||
skin_str = sprintf("%sreplace ZombieBody %S\n", skin_str, shader_name);
|
skin_str = sprintf("%sreplace ZombieBody %S\n", skin_str, shader_name);
|
||||||
skin_str = sprintf("%sreplace ZombieHead %S\n", skin_str, shader_name);
|
skin_str = sprintf("%sreplace ZombieHead %S\n", skin_str, shader_name);
|
||||||
skin_str = sprintf("%sreplace ZombieArmL %S\n", skin_str, shader_name);
|
skin_str = sprintf("%sreplace ZombieArmL %S\n", skin_str, shader_name);
|
||||||
|
|
|
@ -13,6 +13,8 @@ float zombie_anim_walk2_modelindex;
|
||||||
float zombie_anim_walk3_modelindex;
|
float zombie_anim_walk3_modelindex;
|
||||||
float zombie_anim_jog1_modelindex;
|
float zombie_anim_jog1_modelindex;
|
||||||
float zombie_anim_run1_modelindex;
|
float zombie_anim_run1_modelindex;
|
||||||
|
float zombie_anim_climbledge_modelindex;
|
||||||
|
|
||||||
|
|
||||||
#define AI_STATE_PATHING 0
|
#define AI_STATE_PATHING 0
|
||||||
#define AI_STATE_TRAVERSING 1
|
#define AI_STATE_TRAVERSING 1
|
||||||
|
@ -59,7 +61,6 @@ class AI_Chase : entity {
|
||||||
float substate;
|
float substate;
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Traversal state vars
|
// Traversal state vars
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
@ -69,12 +70,10 @@ class AI_Chase : entity {
|
||||||
|
|
||||||
// Think callback executed every logic tick, independent of current animation
|
// Think callback executed every logic tick, independent of current animation
|
||||||
virtual void() think_callback = SUB_Null;
|
virtual void() think_callback = SUB_Null;
|
||||||
// We also have a frame callback that's called each time a new animation frame is reached
|
// // We also have a frame callback that's called each time a new animation frame is reached
|
||||||
virtual void() frame_callback = SUB_Null;
|
// virtual void() frame_callback = SUB_Null;
|
||||||
|
|
||||||
|
|
||||||
float think_delta_time; // Time (in seconds) between entity's ".think()" invocations
|
float think_delta_time; // Time (in seconds) between entity's ".think()" invocations
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
// Animation variables
|
// Animation variables
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
|
@ -85,27 +84,21 @@ class AI_Chase : entity {
|
||||||
float cur_anim_last_time; // Time into the animation at which the last `think` was invoked
|
float cur_anim_last_time; // Time into the animation at which the last `think` was invoked
|
||||||
float cur_anim_playback_speed; // 1.0 = Normal speed, 2.0 = Twice as fast, 0.5 = Half-speed, etc.
|
float cur_anim_playback_speed; // 1.0 = Normal speed, 2.0 = Twice as fast, 0.5 = Half-speed, etc.
|
||||||
// float cur_anim_move_dist;
|
// float cur_anim_move_dist;
|
||||||
|
// Cached derived vars:
|
||||||
|
float cur_anim_duration; // Length (in seconds) of current animation at 1.0 playback speed
|
||||||
|
|
||||||
// --- Next / Queued animation vars ---
|
// --- Next / Queued animation vars ---
|
||||||
float next_anim_model_idx;
|
float next_anim_model_idx;
|
||||||
float next_anim_framegroup;
|
float next_anim_framegroup;
|
||||||
float next_anim_playback_speed;
|
float next_anim_playback_speed;
|
||||||
|
|
||||||
|
|
||||||
float pathfind_result_idx; // TODO - Need to increment this on instantiation
|
float pathfind_result_idx; // TODO - Need to increment this on instantiation
|
||||||
float pathfind_cur_point_idx;
|
float pathfind_cur_point_idx;
|
||||||
|
|
||||||
|
|
||||||
// TODO - Move this to AI_Zombie subclass?
|
// TODO - Move this to AI_Zombie subclass?
|
||||||
float limbs_state;
|
float limbs_state;
|
||||||
|
|
||||||
|
|
||||||
// Constructor. Called when calling `spawn(AI_Chase);`
|
|
||||||
// virtual void() AI_Chase;
|
|
||||||
// void() AI_Chase::think = {
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Animation movement integration fields / code
|
// Animation movement integration fields / code
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -118,7 +111,357 @@ class AI_Chase : entity {
|
||||||
|
|
||||||
// Returns the fraction of an event that overlaps with the saerch region
|
// Returns the fraction of an event that overlaps with the saerch region
|
||||||
// The search region is defined over: [this.cur_anim_move_region_start_time, this.cur_anim_move_region_end_time]
|
// The search region is defined over: [this.cur_anim_move_region_start_time, this.cur_anim_move_region_end_time]
|
||||||
virtual float(float event_start_time, float event_end_time) anim_move_get_event_intersection = {
|
virtual float(float event_start_time, float event_end_time) anim_move_get_event_intersection;
|
||||||
|
|
||||||
|
// Callback for built-in `processmodelevents` to integrate all animation movement between two timestamps
|
||||||
|
virtual void(float event_timestamp, int event_code, string event_data) anim_move_accumulate_iqm_event_movement;
|
||||||
|
virtual float() calc_anim_movement_speed;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
virtual void (float move_speed) do_walk_to_goal;
|
||||||
|
virtual float(entity to, float sendflags) send_entity_func;
|
||||||
|
|
||||||
|
// Constructor. Called when calling `spawn(AI_Chase);`
|
||||||
|
virtual void() AI_Chase;
|
||||||
|
|
||||||
|
// void() take_damage = {
|
||||||
|
// // TODO - Update limb states, mark as needing networking
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual void(float timestamp, int event_code, string event_data) handle_iqm_event;
|
||||||
|
|
||||||
|
// Stop what you're doing and play this animation immediately.
|
||||||
|
virtual void(float anim_model_idx, float anim_framegroup) play_anim;
|
||||||
|
|
||||||
|
// Queue up another animation to play when the current one finishes
|
||||||
|
virtual void(float anim_model_idx, float anim_framegroup) queue_anim;
|
||||||
|
|
||||||
|
// The "logic tick" of the entity.
|
||||||
|
virtual void() think;
|
||||||
|
|
||||||
|
|
||||||
|
// virtual void () fg_die = {};
|
||||||
|
// virtual void () fg_walk = {};
|
||||||
|
// virtual void () fg_attack = {};
|
||||||
|
// virtual void () fg_idle = {};
|
||||||
|
// virtual void (float dist) do_walk_to_goal;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void zombie_traversal_logic() {
|
||||||
|
// AI_Zombie zombie_ent = (AI_Zombie) self;
|
||||||
|
AI_Chase zombie_ent = (AI_Chase) self;
|
||||||
|
|
||||||
|
float traversal_idx = zombie_ent.cur_traversal_idx;
|
||||||
|
vector start_pos = sv_navmesh_traversals[traversal_idx].start_pos;
|
||||||
|
vector midpoint_pos;
|
||||||
|
vector end_pos = sv_navmesh_get_traversal_end_pos(traversal_idx);
|
||||||
|
|
||||||
|
|
||||||
|
string traversal_type;
|
||||||
|
traversal_type = "ledge";
|
||||||
|
// traversal_type = "leap";
|
||||||
|
// traversal_type = "jump_gap";
|
||||||
|
// traversal_type = "hop_barricade";
|
||||||
|
// traversal_type = "hop_fence";
|
||||||
|
// traversal_type = "window";
|
||||||
|
// traversal_type = "teleport";
|
||||||
|
|
||||||
|
// Jump up logic
|
||||||
|
if(traversal_type == "ledge") {
|
||||||
|
// Adjust zombie angle to its smallest representation
|
||||||
|
zombie_ent.angles.y = ((zombie_ent.angles.y + 180) % 360) - 180;
|
||||||
|
// Apply smallest delta angle
|
||||||
|
float delta_angle = sv_navmesh_traversals[traversal_idx].angle - zombie_ent.angles.y;
|
||||||
|
delta_angle = ((delta_angle + 180) % 360) - 180;
|
||||||
|
zombie_ent.angles.y += 0.5 * delta_angle;
|
||||||
|
|
||||||
|
// Jump up traversal consists of the following substates:
|
||||||
|
// 0: Start traversal, play jump up anim
|
||||||
|
// 1: Wait for jump up anim to complete
|
||||||
|
// 2: Move zombie up to ledge
|
||||||
|
// 3: Play zombie get up animation
|
||||||
|
//
|
||||||
|
// Check height of ledge we're climbing:
|
||||||
|
float traversal_height = end_pos.z - start_pos.z;
|
||||||
|
float traversal_time;
|
||||||
|
float lerp_frac;
|
||||||
|
float anim_time;
|
||||||
|
vector ledge_pos;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Fall down
|
||||||
|
if(traversal_height < 0 ) {
|
||||||
|
if(zombie_ent.substate == 0) {
|
||||||
|
zombie_ent.movetype = MOVETYPE_STEP;
|
||||||
|
// zombie_ent.play_anim(get_anim_frame_zombie_fall, get_anim_length_zombie_fall(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// zombie_ent.queue_anim(get_anim_frame_zombie_fall_loop, get_anim_length_zombie_fall_loop(), ANIM_STOP_TYPE_LOOP);
|
||||||
|
traversal_time = min(-traversal_height * (0.35 / 100.0), 2.0);
|
||||||
|
zombie_ent.cur_traversal_start_time = time;
|
||||||
|
zombie_ent.cur_traversal_end_time = time + traversal_time;
|
||||||
|
zombie_ent.substate = 1;
|
||||||
|
}
|
||||||
|
else if(zombie_ent.substate == 1) {
|
||||||
|
lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
zombie_ent.origin = lerpVector(start_pos, end_pos, lerp_frac * lerp_frac);
|
||||||
|
if(lerp_frac >= 1.0) {
|
||||||
|
// zombie_ent.play_anim(get_anim_frame_zombie_land, get_anim_length_zombie_land(), ANIM_STOP_TYPE_NEXT_ANIM);
|
||||||
|
// zombie_ent.cur_anim_frametime = 0.05;
|
||||||
|
// zombie_ent.queue_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
||||||
|
zombie_ent.state = AI_STATE_PATHING;
|
||||||
|
zombie_ent.movetype = MOVETYPE_WALK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Short ledge
|
||||||
|
// else if(traversal_height < 98) {
|
||||||
|
// makevectors([0, sv_navmesh_traversals[traversal_idx].angle, 0]);
|
||||||
|
// ledge_pos = end_pos - '0 0 72' - v_forward * 21;
|
||||||
|
|
||||||
|
// if(zombie_ent.substate == 0) {
|
||||||
|
// zombie_ent.movetype = MOVETYPE_STEP;
|
||||||
|
// // If short jump up, play short jump / short climb anim
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_jump_low, get_anim_length_zombie_jump_low(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// anim_time = 1;
|
||||||
|
// // anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
||||||
|
// // zombie_ent.cur_traversal_end_time = time + anim_time - (2 * zombie_ent.cur_anim_frametime);
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
||||||
|
// // zombie_ent.cur_traversal_end_time = 0;
|
||||||
|
// // Stash anim stop-time in this variable so we can tell when to proceed: (minus three frames)
|
||||||
|
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + 0.3;
|
||||||
|
// zombie_ent.substate = 1;
|
||||||
|
// }
|
||||||
|
// if(zombie_ent.substate == 1) {
|
||||||
|
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
// zombie_ent.origin = lerpVector(start_pos, ledge_pos, lerp_frac);
|
||||||
|
|
||||||
|
// if(lerp_frac >= 1) {
|
||||||
|
// zombie_ent.substate = 2;
|
||||||
|
// // If short jump up, play short climb anim
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_climb_low, get_anim_length_zombie_climb_low(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// // anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
||||||
|
// anim_time = 1;
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if(zombie_ent.substate == 2) {
|
||||||
|
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
// start_pos = end_pos - '0 0 72' - v_forward * 21;
|
||||||
|
// zombie_ent.origin = lerpVector(start_pos, end_pos, lerp_frac);
|
||||||
|
// if(lerp_frac >= 1.0) {
|
||||||
|
// zombie_ent.state = AI_STATE_PATHING;
|
||||||
|
// zombie_ent.movetype = MOVETYPE_WALK;
|
||||||
|
// // FIXME - Need a better way to revert to walking
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Tall ledge
|
||||||
|
else {
|
||||||
|
makevectors([0, sv_navmesh_traversals[traversal_idx].angle, 0]);
|
||||||
|
// ledge_pos = end_pos - '0 0 98' - v_forward * 28;
|
||||||
|
ledge_pos = end_pos - '0 0 94' - v_forward * 28;
|
||||||
|
|
||||||
|
if(zombie_ent.substate == 0) {
|
||||||
|
zombie_ent.movetype = MOVETYPE_STEP;
|
||||||
|
zombie_ent.play_anim(zombie_anim_climbledge_modelindex, 0);
|
||||||
|
// Wait until jump animation is near completion to start moving zombie
|
||||||
|
zombie_ent.cur_traversal_end_time = time + zombie_ent.cur_anim_duration - 0.3;
|
||||||
|
zombie_ent.substate = 1;
|
||||||
|
|
||||||
|
// zombie_ent.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
||||||
|
// Figure out how fast to move the zombie
|
||||||
|
// float traversal_length = vlen(end_pos - start_pos);
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
}
|
||||||
|
else if(zombie_ent.substate == 1) {
|
||||||
|
if(zombie_ent.cur_traversal_end_time <= time) {
|
||||||
|
// Zombie moves from bottom to top of ledge in fixed time:
|
||||||
|
traversal_time = 0.15; // seconds
|
||||||
|
// TODO - Should we determine how fast the zombie moves based on traversal distance?
|
||||||
|
// TODO Otherwise zombie will always jump up in 0.5 seconds regardless of ledge height
|
||||||
|
zombie_ent.cur_traversal_start_time = time;
|
||||||
|
zombie_ent.cur_traversal_end_time = time + traversal_time;
|
||||||
|
zombie_ent.substate = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(zombie_ent.substate == 2) {
|
||||||
|
// Move zombie up to ledge
|
||||||
|
lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
setorigin(zombie_ent, lerpVector(start_pos, ledge_pos, lerp_frac));
|
||||||
|
|
||||||
|
// Once at ledge, play climb animation:
|
||||||
|
if(lerp_frac >= 1) {
|
||||||
|
zombie_ent.substate = 3;
|
||||||
|
zombie_ent.play_anim(zombie_anim_climbledge_modelindex, 1);
|
||||||
|
zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// Wait until animation near completion to advance
|
||||||
|
zombie_ent.cur_traversal_end_time = time + (zombie_ent.cur_anim_duration - 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(zombie_ent.substate == 3) {
|
||||||
|
lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
setorigin(zombie_ent, lerpVector(ledge_pos, end_pos, lerp_frac));
|
||||||
|
|
||||||
|
if(lerp_frac >= 1.0) {
|
||||||
|
zombie_ent.state = AI_STATE_PATHING;
|
||||||
|
zombie_ent.movetype = MOVETYPE_WALK;
|
||||||
|
// FIXME - Need a better way to revert to walking
|
||||||
|
zombie_ent.play_anim(zombie_anim_walk1_modelindex, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mark to send origin / angles to clients
|
||||||
|
zombie_ent.SendFlags |= 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO - Implement leap
|
||||||
|
// else if(traversal_type == "leap") {
|
||||||
|
// midpoint_pos = sv_navmesh_get_traversal_midpoint_pos(traversal_idx);
|
||||||
|
|
||||||
|
// // Adjust zombie angle to its smallest representation
|
||||||
|
// zombie_ent.angles.y = ((zombie_ent.angles.y + 180) % 360) - 180;
|
||||||
|
// // Apply smallest delta angle
|
||||||
|
// float delta_angle = sv_navmesh_traversals[traversal_idx].angle - zombie_ent.angles.y;
|
||||||
|
// delta_angle = ((delta_angle + 180) % 360) - 180;
|
||||||
|
// zombie_ent.angles.y += 0.5 * delta_angle;
|
||||||
|
|
||||||
|
// // Leap traversal consists of the following substates:
|
||||||
|
// // 0: Play leap animation (frames 218-233)
|
||||||
|
// // 1: Wait for frame 233
|
||||||
|
// // 2: Move zombie across arc to end pos, ends at frame 241
|
||||||
|
// // 3: Wait at endpos for frame 247
|
||||||
|
|
||||||
|
// // TODO - Adjust traversal speed?
|
||||||
|
// // TODO - Break up leap start / leap-mid-air / leap land anims?
|
||||||
|
// // float traversal_length =
|
||||||
|
|
||||||
|
// float lerp_frac;
|
||||||
|
|
||||||
|
// if(zombie_ent.substate == 0) {
|
||||||
|
// zombie_ent.movetype = MOVETYPE_STEP;
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_leap_jump, get_anim_length_zombie_leap_jump(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// zombie_ent.substate = 1;
|
||||||
|
// // Advance to next substate (1->2) after 5 frames
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + (5 * zombie_ent.cur_anim_frametime);
|
||||||
|
// }
|
||||||
|
// else if(zombie_ent.substate == 1) {
|
||||||
|
// if(zombie_ent.cur_traversal_end_time <= time) {
|
||||||
|
// zombie_ent.substate = 2;
|
||||||
|
// // Advance to next substate (2->3) after 8 frames
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + (8 * zombie_ent.cur_anim_frametime);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if(zombie_ent.substate == 2) {
|
||||||
|
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
// zombie_ent.origin = lerp_vector_bezier(start_pos, midpoint_pos, end_pos, lerp_frac);
|
||||||
|
|
||||||
|
// if(lerp_frac >= 1) {
|
||||||
|
// zombie_ent.substate = 3;
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_leap_land, get_anim_length_zombie_leap_land(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// float anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
||||||
|
// // Finish traversal at the end of the land animation
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if(zombie_ent.substate == 3) {
|
||||||
|
// if(zombie_ent.cur_traversal_end_time <= time) {
|
||||||
|
// zombie_ent.state = AI_STATE_PATHING;
|
||||||
|
// zombie_ent.movetype = MOVETYPE_WALK;
|
||||||
|
// // FIXME - Need a better way to revert to walking
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // Starting traversal
|
||||||
|
// if(zombie_ent.substate == 0) {
|
||||||
|
// zombie_ent.velocity = '0 0 0';
|
||||||
|
// // zombie_ent.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
||||||
|
// // Start zombie animation:
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_window_hop, get_anim_length_zombie_window_hop(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// // zombie_ent.play_anim(get_anim_frame_zombie_jump_climb, get_anim_length_zombie_jump_climb(), ANIM_STOP_TYPE_STOP);
|
||||||
|
// // zombie_ent.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
||||||
|
// // Figure out how fast to move the zombie
|
||||||
|
// float traversal_length = vlen(end_pos - start_pos);
|
||||||
|
// float anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
||||||
|
|
||||||
|
// zombie_ent.cur_traversal_start_time = time;
|
||||||
|
// // FIXME - Some traversals will have a different way of getting speed...
|
||||||
|
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
||||||
|
// zombie_ent.substate = 1;
|
||||||
|
// zombie_ent.movetype = MOVETYPE_STEP;
|
||||||
|
// zombie_ent.angles.y = sv_navmesh_traversals[traversal_idx].angle;
|
||||||
|
// }
|
||||||
|
// // Moving zombie across traversal
|
||||||
|
// if(zombie_ent.substate == 1) {
|
||||||
|
// float lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
||||||
|
|
||||||
|
// if(lerp_frac > 1.0) {
|
||||||
|
// zombie_ent.state = AI_STATE_PATHING;
|
||||||
|
// zombie_ent.movetype = MOVETYPE_WALK;
|
||||||
|
|
||||||
|
// // TODO - How to tell zombie to play walk anim again?
|
||||||
|
// // FIXME - This ain't right
|
||||||
|
// zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // If the traversal uses the midpoint, lerp across midpoint
|
||||||
|
// if(sv_navmesh_traversals[zombie_ent.cur_traversal_idx].use_midpoint) {
|
||||||
|
// print("Current lerpfrac: ", ftos(lerp_frac), "\n");
|
||||||
|
// midpoint_pos = sv_navmesh_get_traversal_midpoint_pos(traversal_idx);
|
||||||
|
// // Lerp from start to midpoint
|
||||||
|
// if(lerp_frac < 0.5) {
|
||||||
|
// zombie_ent.origin = lerpVector(start_pos, midpoint_pos, lerp_frac * 2.0);
|
||||||
|
// }
|
||||||
|
// // Lerp from midpoint to end
|
||||||
|
// else {
|
||||||
|
// zombie_ent.origin = lerpVector(midpoint_pos, end_pos, (lerp_frac - 0.5) * 2.0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // Otherwise, lerp from start to end
|
||||||
|
// else {
|
||||||
|
// zombie_ent.origin = lerpVector(start_pos, end_pos, lerp_frac);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // TODO - Moving
|
||||||
|
// // vector start_pos = sv_navmesh_traversals[traversal_idx].start_pos;
|
||||||
|
// // vector end_pos = sv_navmesh_get_traversal_end_pos(traversal_idx);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the fraction of an event that overlaps with the saerch region
|
||||||
|
// The search region is defined over: [this.cur_anim_move_region_start_time, this.cur_anim_move_region_end_time]
|
||||||
|
float(float event_start_time, float event_end_time) AI_Chase::anim_move_get_event_intersection {
|
||||||
if(event_end_time < this.cur_anim_move_region_start_time) {
|
if(event_end_time < this.cur_anim_move_region_start_time) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -134,13 +477,12 @@ class AI_Chase : entity {
|
||||||
float overlap_end_lerp_frac = (overlap_end - event_start_time) / (event_end_time - event_start_time);
|
float overlap_end_lerp_frac = (overlap_end - event_start_time) / (event_end_time - event_start_time);
|
||||||
float overlap = overlap_end_lerp_frac - overlap_start_lerp_frac;
|
float overlap = overlap_end_lerp_frac - overlap_start_lerp_frac;
|
||||||
return overlap;
|
return overlap;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Callback for built-in `processmodelevents` to integrate all animation movement between two timestamps
|
// Callback for built-in `processmodelevents` to integrate all animation movement between two timestamps
|
||||||
virtual void(float event_timestamp, int event_code, string event_data) anim_move_accumulate_iqm_event_movement = {
|
void(float event_timestamp, int event_code, string event_data) AI_Chase::anim_move_accumulate_iqm_event_movement {
|
||||||
if(event_code == IQM_EVENT_MOVE_SPEED) {
|
if(event_code == IQM_EVENT_MOVE_SPEED) {
|
||||||
float event_dist = stof(event_data);
|
float event_dist = stof(event_data);
|
||||||
float anim_duration = frameduration(this.cur_anim_model_idx, this.cur_anim_framegroup);
|
|
||||||
float anim_looped = true; // FIXME - Assumes all anims are looped. Is there any way to tell whether an animation is looped?
|
float anim_looped = true; // FIXME - Assumes all anims are looped. Is there any way to tell whether an animation is looped?
|
||||||
|
|
||||||
float last_event_start_time = this.cur_anim_move_last_event_start;
|
float last_event_start_time = this.cur_anim_move_last_event_start;
|
||||||
|
@ -158,25 +500,24 @@ class AI_Chase : entity {
|
||||||
if(anim_looped == false) {
|
if(anim_looped == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
last_event_start_time += anim_duration;
|
last_event_start_time += this.cur_anim_duration;
|
||||||
last_event_end_time += anim_duration;
|
last_event_end_time += this.cur_anim_duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store current event as last event
|
// Store current event as last event
|
||||||
this.cur_anim_move_last_event_dist = event_dist;
|
this.cur_anim_move_last_event_dist = event_dist;
|
||||||
this.cur_anim_move_last_event_start = event_timestamp;
|
this.cur_anim_move_last_event_start = event_timestamp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual float() calc_anim_movement_speed {
|
float() AI_Chase::calc_anim_movement_speed {
|
||||||
float walk_dist = 0;
|
float walk_dist = 0;
|
||||||
// Given current animation state, read through the IQM events to determine exactly how much to move at this logic tick
|
// Given current animation state, read through the IQM events to determine exactly how much to move at this logic tick
|
||||||
// float prev_time = time - ent.think_delta_time;
|
// float prev_time = time - ent.think_delta_time;
|
||||||
|
|
||||||
|
|
||||||
float anim_duration = frameduration(this.cur_anim_model_idx, this.cur_anim_framegroup);
|
// float anim_last_frametime = this.cur_anim_last_time % this.cur_anim_duration;
|
||||||
// float anim_last_frametime = this.cur_anim_last_time % anim_duration;
|
// float anim_cur_frametime = ((time - this.cur_anim_start_time) * this.cur_anim_playback_speed) % this.cur_anim_duration;
|
||||||
// float anim_cur_frametime = ((time - this.cur_anim_start_time) * this.cur_anim_playback_speed) % anim_duration;
|
|
||||||
float anim_last_frametime = this.cur_anim_last_time;
|
float anim_last_frametime = this.cur_anim_last_time;
|
||||||
float anim_cur_frametime = ((time - this.cur_anim_start_time) * this.cur_anim_playback_speed);
|
float anim_cur_frametime = ((time - this.cur_anim_start_time) * this.cur_anim_playback_speed);
|
||||||
|
|
||||||
|
@ -190,17 +531,17 @@ class AI_Chase : entity {
|
||||||
// Wrap anim_last_frametime so it falls within [0, anim_duration]
|
// Wrap anim_last_frametime so it falls within [0, anim_duration]
|
||||||
// Then make anim_cur_frametime relative to that (not wrapped)
|
// Then make anim_cur_frametime relative to that (not wrapped)
|
||||||
this.cur_anim_move_region_end_time = anim_cur_frametime - anim_last_frametime; // First set it to delta
|
this.cur_anim_move_region_end_time = anim_cur_frametime - anim_last_frametime; // First set it to delta
|
||||||
this.cur_anim_move_region_start_time = anim_last_frametime % anim_duration; // Wrap `last_frametime`
|
this.cur_anim_move_region_start_time = anim_last_frametime % this.cur_anim_duration; // Wrap `last_frametime`
|
||||||
this.cur_anim_move_region_end_time += this.cur_anim_move_region_start_time; // Add `start_time` back in to get region end relative to region start
|
this.cur_anim_move_region_end_time += this.cur_anim_move_region_start_time; // Add `start_time` back in to get region end relative to region start
|
||||||
|
|
||||||
// Search through the entire animation:
|
// Search through the entire animation:
|
||||||
float region_start = 0;
|
float region_start = 0;
|
||||||
float region_end = anim_duration + 1;
|
float region_end = this.cur_anim_duration + 1;
|
||||||
// print("Accumulating moves over: (", ftos(region_start), ",", ftos(region_end), "), Search range: (", ftos(this.cur_anim_move_region_start_time));
|
// print("Accumulating moves over: (", ftos(region_start), ",", ftos(region_end), "), Search range: (", ftos(this.cur_anim_move_region_start_time));
|
||||||
// print(",", ftos(this.cur_anim_move_region_end_time),").\n");
|
// print(",", ftos(this.cur_anim_move_region_end_time),").\n");
|
||||||
processmodelevents(this.cur_anim_model_idx, this.cur_anim_framegroup, region_start, region_end, this.anim_move_accumulate_iqm_event_movement);
|
processmodelevents(this.cur_anim_model_idx, this.cur_anim_framegroup, region_start, region_end, this.anim_move_accumulate_iqm_event_movement);
|
||||||
// Call one more time so the final event has a chance to be deposited
|
// Call one more time so the final event has a chance to be deposited
|
||||||
this.anim_move_accumulate_iqm_event_movement(anim_duration, IQM_EVENT_MOVE_SPEED, "0");
|
this.anim_move_accumulate_iqm_event_movement(this.cur_anim_duration, IQM_EVENT_MOVE_SPEED, "0");
|
||||||
// print("\tFinal Result: ",ftos(this.cur_anim_move_dist),"\n");
|
// print("\tFinal Result: ",ftos(this.cur_anim_move_dist),"\n");
|
||||||
walk_dist = this.cur_anim_move_dist;
|
walk_dist = this.cur_anim_move_dist;
|
||||||
|
|
||||||
|
@ -209,13 +550,13 @@ class AI_Chase : entity {
|
||||||
// To get speed, we simply divide by think_delta_time, no?
|
// To get speed, we simply divide by think_delta_time, no?
|
||||||
float movement_speed = walk_dist / this.think_delta_time;
|
float movement_speed = walk_dist / this.think_delta_time;
|
||||||
return movement_speed;
|
return movement_speed;
|
||||||
};
|
};
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void (float move_speed) do_walk_to_goal = {
|
void (float move_speed) AI_Chase::do_walk_to_goal {
|
||||||
if(move_speed == 0) {
|
if(move_speed == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -248,10 +589,6 @@ class AI_Chase : entity {
|
||||||
this.state = AI_STATE_TRAVERSING;
|
this.state = AI_STATE_TRAVERSING;
|
||||||
this.substate = 0;
|
this.substate = 0;
|
||||||
this.cur_traversal_idx = res->point_path_traversals[this.pathfind_cur_point_idx];
|
this.cur_traversal_idx = res->point_path_traversals[this.pathfind_cur_point_idx];
|
||||||
print("Setting state to traversing.\n");
|
|
||||||
vector traversal_end_pos = sv_navmesh_get_traversal_end_pos(res->point_path_traversals[this.pathfind_cur_point_idx]);
|
|
||||||
print("Setting origin to end position: ", vtos(traversal_end_pos), "\n");
|
|
||||||
this.origin = traversal_end_pos;
|
|
||||||
}
|
}
|
||||||
this.pathfind_cur_point_idx += 1;
|
this.pathfind_cur_point_idx += 1;
|
||||||
goal_pos = res->point_path_points[this.pathfind_cur_point_idx];
|
goal_pos = res->point_path_points[this.pathfind_cur_point_idx];
|
||||||
|
@ -286,10 +623,10 @@ class AI_Chase : entity {
|
||||||
new_velocity_z = this.velocity_z;
|
new_velocity_z = this.velocity_z;
|
||||||
this.velocity = new_velocity;
|
this.velocity = new_velocity;
|
||||||
this.SendFlags |= 1;
|
this.SendFlags |= 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
virtual float(entity to, float sendflags) send_entity_func = {
|
float(entity to, float sendflags) AI_Chase::send_entity_func {
|
||||||
WriteByte(MSG_ENTITY, ENT_TYPE_ZOMBIE);
|
WriteByte(MSG_ENTITY, ENT_TYPE_ZOMBIE);
|
||||||
// Write bytflags indicating payload contents
|
// Write bytflags indicating payload contents
|
||||||
WriteByte(MSG_ENTITY, sendflags);
|
WriteByte(MSG_ENTITY, sendflags);
|
||||||
|
@ -332,12 +669,12 @@ class AI_Chase : entity {
|
||||||
}
|
}
|
||||||
// TODO - Send limb state / texture info
|
// TODO - Send limb state / texture info
|
||||||
return TRUE;
|
return TRUE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Constructor. Called when calling `spawn(AI_Chase);`
|
// Constructor. Called when calling `spawn(AI_Chase);`
|
||||||
virtual void() AI_Chase = {
|
void() AI_Chase::AI_Chase {
|
||||||
this.path_target = world;
|
this.path_target = world;
|
||||||
// this.path_pos = world.origin;
|
// this.path_pos = world.origin;
|
||||||
this.cur_anim_model_idx = -1;
|
this.cur_anim_model_idx = -1;
|
||||||
|
@ -348,13 +685,13 @@ class AI_Chase : entity {
|
||||||
// Should this be done in constructor?
|
// Should this be done in constructor?
|
||||||
this.SendEntity = this.send_entity_func;
|
this.SendEntity = this.send_entity_func;
|
||||||
this.cur_anim_playback_speed = 1;
|
this.cur_anim_playback_speed = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// void() take_damage = {
|
// void() take_damage = {
|
||||||
// // TODO - Update limb states, mark as needing networking
|
// // TODO - Update limb states, mark as needing networking
|
||||||
// }
|
// }
|
||||||
|
|
||||||
virtual void(float timestamp, int event_code, string event_data) handle_iqm_event = {
|
void(float timestamp, int event_code, string event_data) AI_Chase::handle_iqm_event {
|
||||||
switch(event_code) {
|
switch(event_code) {
|
||||||
// case IQM_EVENT_MOVE_SPEED: // FRAME MOVEMENT DIST
|
// case IQM_EVENT_MOVE_SPEED: // FRAME MOVEMENT DIST
|
||||||
// this.cur_anim_move_dist += stof(event_data);
|
// this.cur_anim_move_dist += stof(event_data);
|
||||||
|
@ -366,29 +703,30 @@ class AI_Chase : entity {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stop what you're doing and play this animation immediately.
|
// Stop what you're doing and play this animation immediately.
|
||||||
virtual void(float anim_model_idx, float anim_framegroup) play_anim {
|
void(float anim_model_idx, float anim_framegroup) AI_Chase::play_anim {
|
||||||
this.cur_anim_model_idx = anim_model_idx;
|
this.cur_anim_model_idx = anim_model_idx;
|
||||||
this.cur_anim_framegroup = 0;
|
this.cur_anim_framegroup = anim_framegroup;
|
||||||
this.cur_anim_start_time = time;
|
this.cur_anim_start_time = time;
|
||||||
this.cur_anim_last_time = 0;
|
this.cur_anim_last_time = 0;
|
||||||
this.cur_anim_playback_speed = 1; // Reset value
|
this.cur_anim_playback_speed = 1; // Reset value
|
||||||
|
this.cur_anim_duration = frameduration(this.cur_anim_model_idx, this.cur_anim_framegroup);
|
||||||
// Indicate that we need to broadcast the current anim frame info:
|
// Indicate that we need to broadcast the current anim frame info:
|
||||||
self.SendFlags |= 2; // Indicate that we should update client-side animations
|
self.SendFlags |= 2; // Indicate that we should update client-side animations
|
||||||
};
|
};
|
||||||
|
|
||||||
// Queue up another animation to play when the current one finishes
|
// Queue up another animation to play when the current one finishes
|
||||||
virtual void(float anim_model_idx, float anim_framegroup) queue_anim {
|
void(float anim_model_idx, float anim_framegroup) AI_Chase::queue_anim {
|
||||||
this.next_anim_model_idx = anim_model_idx;
|
this.next_anim_model_idx = anim_model_idx;
|
||||||
this.next_anim_framegroup = anim_framegroup;
|
this.next_anim_framegroup = anim_framegroup;
|
||||||
this.next_anim_playback_speed = 1.0;
|
this.next_anim_playback_speed = 1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// The "logic tick" of the entity.
|
// The "logic tick" of the entity.
|
||||||
virtual void() think = {
|
void() AI_Chase::think {
|
||||||
if(this.cur_anim_model_idx >= 0) {
|
if(this.cur_anim_model_idx >= 0) {
|
||||||
// print("Think!, ", ftos(cur_anim_time));
|
// print("Think!, ", ftos(cur_anim_time));
|
||||||
float cur_anim_time = (time - this.cur_anim_start_time) * this.cur_anim_playback_speed;
|
float cur_anim_time = (time - this.cur_anim_start_time) * this.cur_anim_playback_speed;
|
||||||
|
@ -402,12 +740,9 @@ class AI_Chase : entity {
|
||||||
skel_blend_data.animationtime[0] = cur_anim_time;
|
skel_blend_data.animationtime[0] = cur_anim_time;
|
||||||
skel_build_ptr(this.skeletonindex, 1, &skel_blend_data, sizeof(skel_blend_data));
|
skel_build_ptr(this.skeletonindex, 1, &skel_blend_data, sizeof(skel_blend_data));
|
||||||
|
|
||||||
// Zero out for this frame, we're going to accumulate total distance to move here via `processmodelevents`
|
|
||||||
// this.cur_anim_move_dist = 0;
|
|
||||||
// Process all animation frame events that elapsed since the last `think` function was called
|
// Process all animation frame events that elapsed since the last `think` function was called
|
||||||
float anim_duration = frameduration(this.cur_anim_model_idx, this.cur_anim_framegroup);
|
float events_start_time = this.cur_anim_last_time % this.cur_anim_duration;
|
||||||
float events_start_time = this.cur_anim_last_time % anim_duration;
|
float events_end_time = cur_anim_time % this.cur_anim_duration;
|
||||||
float events_end_time = cur_anim_time % anim_duration;
|
|
||||||
|
|
||||||
|
|
||||||
// If the animation was looped, and start time is near the anim end, while end time is near the anim start
|
// If the animation was looped, and start time is near the anim end, while end time is near the anim start
|
||||||
|
@ -415,7 +750,7 @@ class AI_Chase : entity {
|
||||||
if(events_end_time < events_start_time) {
|
if(events_end_time < events_start_time) {
|
||||||
// Process elapsed events at the end of the animation
|
// Process elapsed events at the end of the animation
|
||||||
float segment_start = events_start_time;
|
float segment_start = events_start_time;
|
||||||
float segment_end = anim_duration;
|
float segment_end = this.cur_anim_duration;
|
||||||
processmodelevents(this.cur_anim_model_idx, this.cur_anim_framegroup, segment_start, segment_end, this.handle_iqm_event);
|
processmodelevents(this.cur_anim_model_idx, this.cur_anim_framegroup, segment_start, segment_end, this.handle_iqm_event);
|
||||||
// Process elapsed events at the start of the animation
|
// Process elapsed events at the start of the animation
|
||||||
segment_start = 0;
|
segment_start = 0;
|
||||||
|
@ -428,7 +763,7 @@ class AI_Chase : entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a queued animation, check if this animation is over (or is very close to being over)
|
// If we have a queued animation, check if this animation is over (or is very close to being over)
|
||||||
if(this.next_anim_model_idx >= 0 && (cur_anim_time + this.think_delta_time * this.cur_anim_playback_speed) >= anim_duration) {
|
if(this.next_anim_model_idx >= 0 && (cur_anim_time + this.think_delta_time * this.cur_anim_playback_speed) >= this.cur_anim_duration) {
|
||||||
this.play_anim( this.next_anim_model_idx, this.next_anim_framegroup);
|
this.play_anim( this.next_anim_model_idx, this.next_anim_framegroup);
|
||||||
this.cur_anim_playback_speed = this.next_anim_playback_speed;
|
this.cur_anim_playback_speed = this.next_anim_playback_speed;
|
||||||
this.SendFlags |= 2; // Indicate that we should update client-side animations
|
this.SendFlags |= 2; // Indicate that we should update client-side animations
|
||||||
|
@ -447,20 +782,13 @@ class AI_Chase : entity {
|
||||||
// Recalculate cur_anim_time, in case another animation was triggered
|
// Recalculate cur_anim_time, in case another animation was triggered
|
||||||
this.cur_anim_last_time = (time - this.cur_anim_start_time) * this.cur_anim_playback_speed;
|
this.cur_anim_last_time = (time - this.cur_anim_start_time) * this.cur_anim_playback_speed;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// virtual void () fg_die = {};
|
|
||||||
// virtual void () fg_walk = {};
|
|
||||||
// virtual void () fg_attack = {};
|
|
||||||
// virtual void () fg_idle = {};
|
|
||||||
// virtual void (float dist) do_walk_to_goal;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// class AI_Zombie : AI_Chase {
|
// class AI_Zombie : AI_Chase {
|
||||||
// entity enemy; // If near, attack
|
// entity enemy; // If near, attack
|
||||||
|
|
||||||
|
@ -518,15 +846,13 @@ void zombie_think_callback() {
|
||||||
}
|
}
|
||||||
else if(zombie.state == AI_STATE_TRAVERSING) {
|
else if(zombie.state == AI_STATE_TRAVERSING) {
|
||||||
// TODO - traversal logic needs to be redone...
|
// TODO - traversal logic needs to be redone...
|
||||||
// zombie_traversal_logic();
|
zombie_traversal_logic();
|
||||||
|
|
||||||
// FIXME - For now, teleport to end of traversal:
|
|
||||||
float traversal_idx = zombie.cur_traversal_idx;
|
|
||||||
vector end_pos = sv_navmesh_get_traversal_end_pos(traversal_idx);
|
|
||||||
setorigin(zombie, end_pos);
|
|
||||||
zombie.state = AI_STATE_PATHING;
|
|
||||||
|
|
||||||
|
|
||||||
|
// // FIXME - For now, teleport to end of traversal:
|
||||||
|
// float traversal_idx = zombie.cur_traversal_idx;
|
||||||
|
// vector end_pos = sv_navmesh_get_traversal_end_pos(traversal_idx);
|
||||||
|
// setorigin(zombie, end_pos);
|
||||||
|
// zombie.state = AI_STATE_PATHING;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -546,6 +872,7 @@ void() test_new_ent = {
|
||||||
precache_model("models/ai/zombie_anim_walk3.iqm");
|
precache_model("models/ai/zombie_anim_walk3.iqm");
|
||||||
precache_model("models/ai/zombie_anim_jog1.iqm");
|
precache_model("models/ai/zombie_anim_jog1.iqm");
|
||||||
precache_model("models/ai/zombie_anim_run1.iqm");
|
precache_model("models/ai/zombie_anim_run1.iqm");
|
||||||
|
precache_model("models/ai/zombie_anim_climbledge.iqm");
|
||||||
zombie_anim_idle_modelindex = getmodelindex("models/ai/zombie_anim_idle.iqm");
|
zombie_anim_idle_modelindex = getmodelindex("models/ai/zombie_anim_idle.iqm");
|
||||||
zombie_anim_rise_modelindex = getmodelindex("models/ai/zombie_anim_rise.iqm");
|
zombie_anim_rise_modelindex = getmodelindex("models/ai/zombie_anim_rise.iqm");
|
||||||
zombie_anim_walk1_modelindex = getmodelindex("models/ai/zombie_anim_walk1.iqm");
|
zombie_anim_walk1_modelindex = getmodelindex("models/ai/zombie_anim_walk1.iqm");
|
||||||
|
@ -553,6 +880,7 @@ void() test_new_ent = {
|
||||||
zombie_anim_walk3_modelindex = getmodelindex("models/ai/zombie_anim_walk3.iqm");
|
zombie_anim_walk3_modelindex = getmodelindex("models/ai/zombie_anim_walk3.iqm");
|
||||||
zombie_anim_jog1_modelindex = getmodelindex("models/ai/zombie_anim_jog1.iqm");
|
zombie_anim_jog1_modelindex = getmodelindex("models/ai/zombie_anim_jog1.iqm");
|
||||||
zombie_anim_run1_modelindex = getmodelindex("models/ai/zombie_anim_run1.iqm");
|
zombie_anim_run1_modelindex = getmodelindex("models/ai/zombie_anim_run1.iqm");
|
||||||
|
zombie_anim_climbledge_modelindex = getmodelindex("models/ai/zombie_anim_climbledge.iqm");
|
||||||
}
|
}
|
||||||
|
|
||||||
AI_Chase zombie = spawn(AI_Chase);
|
AI_Chase zombie = spawn(AI_Chase);
|
||||||
|
@ -589,8 +917,6 @@ void() test_new_ent = {
|
||||||
setmodel(zombie, "models/ai/nazi_zombie.iqm");
|
setmodel(zombie, "models/ai/nazi_zombie.iqm");
|
||||||
skelblend_t skel_blend_data;
|
skelblend_t skel_blend_data;
|
||||||
zombie.skeletonindex = skel_create(zombie.modelindex);
|
zombie.skeletonindex = skel_create(zombie.modelindex);
|
||||||
// TODO - Do an initial skeleton build with the idle animation...
|
|
||||||
skel_blend_data.sourcemodelindex = zombie.skeletonindex; // FIXME - replace this with idle animation...
|
|
||||||
skel_blend_data.sourcemodelindex = zombie_anim_idle_modelindex;
|
skel_blend_data.sourcemodelindex = zombie_anim_idle_modelindex;
|
||||||
skel_blend_data.firstbone = -1;
|
skel_blend_data.firstbone = -1;
|
||||||
skel_blend_data.lastbone = -1;
|
skel_blend_data.lastbone = -1;
|
||||||
|
@ -691,291 +1017,6 @@ void() test_new_ent = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// void zombie_traversal_logic() {
|
|
||||||
// AI_Zombie zombie_ent = (AI_Zombie) self;
|
|
||||||
|
|
||||||
// float traversal_idx = zombie_ent.cur_traversal_idx;
|
|
||||||
// vector start_pos = sv_navmesh_traversals[traversal_idx].start_pos;
|
|
||||||
// vector midpoint_pos;
|
|
||||||
// vector end_pos = sv_navmesh_get_traversal_end_pos(traversal_idx);
|
|
||||||
|
|
||||||
|
|
||||||
// string traversal_type;
|
|
||||||
// // traversal_type = "ledge";
|
|
||||||
// traversal_type = "leap";
|
|
||||||
// // traversal_type = "jump_gap";
|
|
||||||
// // traversal_type = "hop_barricade";
|
|
||||||
// // traversal_type = "hop_fence";
|
|
||||||
// // traversal_type = "window";
|
|
||||||
// // traversal_type = "teleport";
|
|
||||||
|
|
||||||
// // Jump up logic
|
|
||||||
// if(traversal_type == "ledge") {
|
|
||||||
// // Adjust zombie angle to its smallest representation
|
|
||||||
// zombie_ent.angles.y = ((zombie_ent.angles.y + 180) % 360) - 180;
|
|
||||||
// // Apply smallest delta angle
|
|
||||||
// float delta_angle = sv_navmesh_traversals[traversal_idx].angle - zombie_ent.angles.y;
|
|
||||||
// delta_angle = ((delta_angle + 180) % 360) - 180;
|
|
||||||
// zombie_ent.angles.y += 0.5 * delta_angle;
|
|
||||||
|
|
||||||
// // Jump up traversal consists of the following substates:
|
|
||||||
// // 0: Start traversal, play jump up anim
|
|
||||||
// // 1: Wait for jump up anim to complete
|
|
||||||
// // 2: Move zombie up to ledge
|
|
||||||
// // 3: Play zombie get up animation
|
|
||||||
// //
|
|
||||||
// // Check height of ledge we're climbing:
|
|
||||||
// float traversal_height = end_pos.z - start_pos.z;
|
|
||||||
// float traversal_time;
|
|
||||||
// float lerp_frac;
|
|
||||||
// float anim_time;
|
|
||||||
// vector ledge_pos;
|
|
||||||
|
|
||||||
// // Fall down
|
|
||||||
// if(traversal_height < 0 ) {
|
|
||||||
// if(zombie_ent.substate == 0) {
|
|
||||||
// zombie_ent.movetype = MOVETYPE_STEP;
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_fall, get_anim_length_zombie_fall(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// zombie_ent.queue_anim(get_anim_frame_zombie_fall_loop, get_anim_length_zombie_fall_loop(), ANIM_STOP_TYPE_LOOP);
|
|
||||||
// traversal_time = min(-traversal_height * (0.35 / 100.0), 2.0);
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + traversal_time;
|
|
||||||
// zombie_ent.substate = 1;
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 1) {
|
|
||||||
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
// zombie_ent.origin = lerpVector(start_pos, end_pos, lerp_frac * lerp_frac);
|
|
||||||
// if(lerp_frac >= 1.0) {
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_land, get_anim_length_zombie_land(), ANIM_STOP_TYPE_NEXT_ANIM);
|
|
||||||
// zombie_ent.cur_anim_frametime = 0.05;
|
|
||||||
// zombie_ent.queue_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
|
||||||
// zombie_ent.state = AI_STATE_PATHING;
|
|
||||||
// zombie_ent.movetype = MOVETYPE_WALK;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Short ledge
|
|
||||||
// else if(traversal_height < 98) {
|
|
||||||
// makevectors([0, sv_navmesh_traversals[traversal_idx].angle, 0]);
|
|
||||||
// ledge_pos = end_pos - '0 0 72' - v_forward * 21;
|
|
||||||
|
|
||||||
// if(zombie_ent.substate == 0) {
|
|
||||||
// zombie_ent.movetype = MOVETYPE_STEP;
|
|
||||||
// // If short jump up, play short jump / short climb anim
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_jump_low, get_anim_length_zombie_jump_low(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
|
||||||
// // zombie_ent.cur_traversal_end_time = time + anim_time - (2 * zombie_ent.cur_anim_frametime);
|
|
||||||
// zombie_ent.cur_traversal_end_time = 0;
|
|
||||||
// // Stash anim stop-time in this variable so we can tell when to proceed: (minus three frames)
|
|
||||||
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + 0.3;
|
|
||||||
// zombie_ent.substate = 1;
|
|
||||||
// }
|
|
||||||
// if(zombie_ent.substate == 1) {
|
|
||||||
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
// zombie_ent.origin = lerpVector(start_pos, ledge_pos, lerp_frac);
|
|
||||||
|
|
||||||
// if(lerp_frac >= 1) {
|
|
||||||
// zombie_ent.substate = 2;
|
|
||||||
// // If short jump up, play short climb anim
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_climb_low, get_anim_length_zombie_climb_low(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 2) {
|
|
||||||
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
// start_pos = end_pos - '0 0 72' - v_forward * 21;
|
|
||||||
// zombie_ent.origin = lerpVector(start_pos, end_pos, lerp_frac);
|
|
||||||
// if(lerp_frac >= 1.0) {
|
|
||||||
// zombie_ent.state = AI_STATE_PATHING;
|
|
||||||
// zombie_ent.movetype = MOVETYPE_WALK;
|
|
||||||
// // FIXME - Need a better way to revert to walking
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Tall ledge
|
|
||||||
// else {
|
|
||||||
// makevectors([0, sv_navmesh_traversals[traversal_idx].angle, 0]);
|
|
||||||
// ledge_pos = end_pos - '0 0 98' - v_forward * 28;
|
|
||||||
|
|
||||||
// if(zombie_ent.substate == 0) {
|
|
||||||
// zombie_ent.movetype = MOVETYPE_STEP;
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_jump, get_anim_length_zombie_jump(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// // zombie_ent.cur_anim_frametime = 0.08;
|
|
||||||
// anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + anim_time - (1 * zombie_ent.cur_anim_frametime);
|
|
||||||
// // Stash anim stop-time in this variable so we can tell when to proceed: (minus three frames)
|
|
||||||
// zombie_ent.substate = 1;
|
|
||||||
|
|
||||||
// // zombie_ent.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
|
||||||
// // Figure out how fast to move the zombie
|
|
||||||
// // float traversal_length = vlen(end_pos - start_pos);
|
|
||||||
// // zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// // FIXME - Some traversals will have a different way of getting speed...
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 1) {
|
|
||||||
// if(zombie_ent.cur_traversal_end_time <= time) {
|
|
||||||
// // Zombie jumping should be real fast,
|
|
||||||
// traversal_time = 0.12; // seconds
|
|
||||||
// // TODO - Should we determine how fast the zombie moves based on traversal distance?
|
|
||||||
// // TODO Otherwise zombie will always jump up in 0.5 seconds regardless of ledge height
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + traversal_time;
|
|
||||||
// zombie_ent.substate = 2;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 2) {
|
|
||||||
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
// zombie_ent.origin = lerpVector(start_pos, ledge_pos, lerp_frac);
|
|
||||||
|
|
||||||
|
|
||||||
// if(lerp_frac >= 1) {
|
|
||||||
// zombie_ent.substate = 3;
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_climb, get_anim_length_zombie_climb(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 3) {
|
|
||||||
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
// zombie_ent.origin = lerpVector(ledge_pos, end_pos, lerp_frac);
|
|
||||||
// if(lerp_frac >= 1.0) {
|
|
||||||
// zombie_ent.state = AI_STATE_PATHING;
|
|
||||||
// zombie_ent.movetype = MOVETYPE_WALK;
|
|
||||||
// // FIXME - Need a better way to revert to walking
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// else if(traversal_type == "leap") {
|
|
||||||
// midpoint_pos = sv_navmesh_get_traversal_midpoint_pos(traversal_idx);
|
|
||||||
|
|
||||||
// // Adjust zombie angle to its smallest representation
|
|
||||||
// zombie_ent.angles.y = ((zombie_ent.angles.y + 180) % 360) - 180;
|
|
||||||
// // Apply smallest delta angle
|
|
||||||
// float delta_angle = sv_navmesh_traversals[traversal_idx].angle - zombie_ent.angles.y;
|
|
||||||
// delta_angle = ((delta_angle + 180) % 360) - 180;
|
|
||||||
// zombie_ent.angles.y += 0.5 * delta_angle;
|
|
||||||
|
|
||||||
// // Leap traversal consists of the following substates:
|
|
||||||
// // 0: Play leap animation (frames 218-233)
|
|
||||||
// // 1: Wait for frame 233
|
|
||||||
// // 2: Move zombie across arc to end pos, ends at frame 241
|
|
||||||
// // 3: Wait at endpos for frame 247
|
|
||||||
|
|
||||||
// // TODO - Adjust traversal speed?
|
|
||||||
// // TODO - Break up leap start / leap-mid-air / leap land anims?
|
|
||||||
// // float traversal_length =
|
|
||||||
|
|
||||||
// float lerp_frac;
|
|
||||||
|
|
||||||
// if(zombie_ent.substate == 0) {
|
|
||||||
// zombie_ent.movetype = MOVETYPE_STEP;
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_leap_jump, get_anim_length_zombie_leap_jump(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// zombie_ent.substate = 1;
|
|
||||||
// // Advance to next substate (1->2) after 5 frames
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + (5 * zombie_ent.cur_anim_frametime);
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 1) {
|
|
||||||
// if(zombie_ent.cur_traversal_end_time <= time) {
|
|
||||||
// zombie_ent.substate = 2;
|
|
||||||
// // Advance to next substate (2->3) after 8 frames
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + (8 * zombie_ent.cur_anim_frametime);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 2) {
|
|
||||||
// lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
// zombie_ent.origin = lerp_vector_bezier(start_pos, midpoint_pos, end_pos, lerp_frac);
|
|
||||||
|
|
||||||
// if(lerp_frac >= 1) {
|
|
||||||
// zombie_ent.substate = 3;
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_leap_land, get_anim_length_zombie_leap_land(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// float anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
|
||||||
// // Finish traversal at the end of the land animation
|
|
||||||
// zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// zombie_ent.cur_traversal_end_time = time + anim_time;
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if(zombie_ent.substate == 3) {
|
|
||||||
// if(zombie_ent.cur_traversal_end_time <= time) {
|
|
||||||
// zombie_ent.state = AI_STATE_PATHING;
|
|
||||||
// zombie_ent.movetype = MOVETYPE_WALK;
|
|
||||||
// // FIXME - Need a better way to revert to walking
|
|
||||||
// zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // // Starting traversal
|
|
||||||
// // if(zombie_ent.substate == 0) {
|
|
||||||
// // zombie_ent.velocity = '0 0 0';
|
|
||||||
// // // zombie_ent.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
|
||||||
// // // Start zombie animation:
|
|
||||||
// // // zombie_ent.play_anim(get_anim_frame_zombie_window_hop, get_anim_length_zombie_window_hop(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// // // zombie_ent.play_anim(get_anim_frame_zombie_jump_climb, get_anim_length_zombie_jump_climb(), ANIM_STOP_TYPE_STOP);
|
|
||||||
// // // zombie_ent.cur_anim_get_frame_func = (float(float)) SUB_Null;
|
|
||||||
// // // Figure out how fast to move the zombie
|
|
||||||
// // float traversal_length = vlen(end_pos - start_pos);
|
|
||||||
// // float anim_time = (zombie_ent.cur_anim_length - 1) * zombie_ent.cur_anim_frametime;
|
|
||||||
|
|
||||||
// // zombie_ent.cur_traversal_start_time = time;
|
|
||||||
// // // FIXME - Some traversals will have a different way of getting speed...
|
|
||||||
// // zombie_ent.cur_traversal_end_time = time + anim_time;
|
|
||||||
// // zombie_ent.substate = 1;
|
|
||||||
// // zombie_ent.movetype = MOVETYPE_STEP;
|
|
||||||
// // zombie_ent.angles.y = sv_navmesh_traversals[traversal_idx].angle;
|
|
||||||
// // }
|
|
||||||
// // // Moving zombie across traversal
|
|
||||||
// // if(zombie_ent.substate == 1) {
|
|
||||||
// // float lerp_frac = (time - zombie_ent.cur_traversal_start_time) / (zombie_ent.cur_traversal_end_time - zombie_ent.cur_traversal_start_time);
|
|
||||||
|
|
||||||
// // if(lerp_frac > 1.0) {
|
|
||||||
// // zombie_ent.state = AI_STATE_PATHING;
|
|
||||||
// // zombie_ent.movetype = MOVETYPE_WALK;
|
|
||||||
|
|
||||||
// // // TODO - How to tell zombie to play walk anim again?
|
|
||||||
// // // FIXME - This ain't right
|
|
||||||
// // zombie_ent.play_anim(get_anim_frame_zombie_walk1, get_anim_length_zombie_walk1(), ANIM_STOP_TYPE_LOOP);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // // If the traversal uses the midpoint, lerp across midpoint
|
|
||||||
// // if(sv_navmesh_traversals[zombie_ent.cur_traversal_idx].use_midpoint) {
|
|
||||||
// // print("Current lerpfrac: ", ftos(lerp_frac), "\n");
|
|
||||||
// // midpoint_pos = sv_navmesh_get_traversal_midpoint_pos(traversal_idx);
|
|
||||||
// // // Lerp from start to midpoint
|
|
||||||
// // if(lerp_frac < 0.5) {
|
|
||||||
// // zombie_ent.origin = lerpVector(start_pos, midpoint_pos, lerp_frac * 2.0);
|
|
||||||
// // }
|
|
||||||
// // // Lerp from midpoint to end
|
|
||||||
// // else {
|
|
||||||
// // zombie_ent.origin = lerpVector(midpoint_pos, end_pos, (lerp_frac - 0.5) * 2.0);
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// // // Otherwise, lerp from start to end
|
|
||||||
// // else {
|
|
||||||
// // zombie_ent.origin = lerpVector(start_pos, end_pos, lerp_frac);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // // TODO - Moving
|
|
||||||
// // // vector start_pos = sv_navmesh_traversals[traversal_idx].start_pos;
|
|
||||||
// // // vector end_pos = sv_navmesh_get_traversal_end_pos(traversal_idx);
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue