mirror of
https://github.com/nzp-team/quakec.git
synced 2025-02-21 11:11:42 +00:00
SERVER Add IQM Zombie Revamp
CLIENT: Add drawing of IQM Zombie Revamp
This commit is contained in:
parent
e463a671d2
commit
1c0f9889d9
8 changed files with 1077 additions and 1158 deletions
|
@ -571,8 +571,12 @@ void cl_navmesh_editor_draw() {
|
|||
cl_navmesh_draw_traversal(i);
|
||||
}
|
||||
|
||||
cl_navmesh_draw_test_ent(startent_pos, [1,1,1], [0,1,0], 0.4);
|
||||
cl_navmesh_draw_test_ent(goalent_pos, [1,1,1], [1,0,0], 0.4);
|
||||
if(startent_set) {
|
||||
cl_navmesh_draw_test_ent(startent_pos, [1,1,1], [0,1,0], 0.4);
|
||||
}
|
||||
if(goalent_set) {
|
||||
cl_navmesh_draw_test_ent(goalent_pos, [1,1,1], [1,0,0], 0.4);
|
||||
}
|
||||
|
||||
cl_navmesh_pathfind_draw_result_path();
|
||||
cl_navmesh_pathfind_draw_result_portals();
|
||||
|
@ -2025,8 +2029,10 @@ void cl_navmesh_editor_load_navmesh() {
|
|||
|
||||
float(float start, float goal, vector start_pos, vector end_pos) cl_navmesh_pathfind_start;
|
||||
|
||||
void cl_navmesh_draw_test_ent(vector pos, vector scale, vector color, float alpha)
|
||||
{
|
||||
void cl_navmesh_draw_test_ent(vector pos, vector scale, vector color, float alpha) {
|
||||
|
||||
|
||||
|
||||
//Assigning the shader as something else so that fte doesn't batch the calls (leading to colors not changing between draw calls)
|
||||
R_BeginPolygon("debug/wireframe",0);
|
||||
R_BeginPolygon("debug/solid_nocull",0);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1293,8 +1293,9 @@ float sv_navmesh_pathfind(entity from, entity to) {
|
|||
// We can perform pathfinding logic without losing our current path.
|
||||
|
||||
// TODO - In pathfinding, I need a reference to the calling entity to know which traversal types this entity can use
|
||||
AI_Chase chase_ent = (AI_Chase) from;
|
||||
navmesh_pathfind_result* res = &(sv_zombie_pathfind_result[chase_ent.pathfind_result_idx]);
|
||||
// AI_Chase chase_ent = (AI_Chase) from;
|
||||
// navmesh_pathfind_result* res = &(sv_zombie_pathfind_result[chase_ent.pathfind_result_idx]);
|
||||
navmesh_pathfind_result* res = &(sv_zombie_pathfind_result[0]); // FIXME
|
||||
|
||||
float start = sv_navmesh_get_containing_poly(from.origin);
|
||||
float goal = sv_navmesh_get_containing_poly(to.origin);
|
||||
|
|
|
@ -483,168 +483,6 @@ navmesh_pathfind_result *sv_zombie_pathfind_result; // Used as primary. The one
|
|||
navmesh_pathfind_result *sv_zombie_pathfind_result_aux; // Used as secondary, so we can pathfind without losing current path
|
||||
#endif // PC
|
||||
|
||||
//=================================================================
|
||||
//========================== AI defs ==============================
|
||||
|
||||
|
||||
// -----------–-----------–-----------–-----------–-----------–-----------–----
|
||||
// Animation Definitions
|
||||
// -----------–-----------–-----------–-----------–-----------–-----------–----
|
||||
// For the animation system, we could define each animation as the start and
|
||||
// end frame range, but we'd like to be able to compose animations out of
|
||||
// frame numbers that are not contiguous (e.g. frames=[0,1,5,6,2,3]).
|
||||
// To pull this off, we need to treat animations as a list of frame numbers.
|
||||
|
||||
// For the animation system, we want to pass around pointers to thse arrays so
|
||||
// that an entity can keep track of the frame list for its current animation.
|
||||
// However, QC only allows for function pointers. Meaning, that if we want to
|
||||
// pass around these animations, then we can only pass them around as function
|
||||
// pointers. Thus, we must create two functions for each frame list, one for
|
||||
// each thing we would need to do to a read-only array:
|
||||
// - access an index
|
||||
// - get the array length
|
||||
|
||||
// To pull this off, we'd need to define the following two functions for
|
||||
// every animation:
|
||||
// float get_anim_frame_zombie_walk1(float frame_idx) {float frames[] = {38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53}; return frames[frame_idx]};
|
||||
// float get_anim_length_zombie_walk1(float frame_idx) {float frames[] = {38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53}; return frames.length};
|
||||
|
||||
// But, instead of doing that for _every_ animation, the following preprocessor
|
||||
// directive will generate the above two functions from the single statement:
|
||||
// DEFINE_ANIM(zombie_walk1, 38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53);
|
||||
|
||||
// After the above statement, the functions `get_anim_frame_zombie_walk1` and
|
||||
// `get_anim_length_zombie_walk1` have been defined and are now available to
|
||||
// use and pass around.
|
||||
// -----------–-----------–-----------–-----------–-----------–-----------–----
|
||||
#define DEFINE_ANIM( ANIM_NAME, ...); \
|
||||
float get_anim_frame_##ANIM_NAME## (float frame_idx) {float frames[] = {__VA_ARGS__}; return frames[frame_idx];}; \
|
||||
float get_anim_length_##ANIM_NAME## () {float frames[] = {__VA_ARGS__}; return frames.length;};
|
||||
// -----------–-----------–-----------–-----------–-----------–-----------–----
|
||||
|
||||
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 state;
|
||||
float substate;
|
||||
|
||||
// -----------------------------
|
||||
// Traversal state vars
|
||||
// -----------------------------
|
||||
float cur_traversal_idx;
|
||||
float cur_traversal_end_time;
|
||||
float cur_traversal_start_time;
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
// ------------------------------
|
||||
// Animation variables
|
||||
// ------------------------------
|
||||
// --- 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;
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
// Reset Animation state Vars
|
||||
this.cur_anim_start_time = time;
|
||||
this.cur_anim_frame_idx = 0;
|
||||
this.frame = anim_frame_func(0);
|
||||
};
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 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 {
|
||||
entity enemy; // If near, attack
|
||||
|
||||
// Constructor. Called when calling `spawn(AI_Zombie);`
|
||||
// virtual void() AI_Zombie = {};
|
||||
// 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;
|
||||
|
||||
// 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};
|
||||
|
||||
//=================================================================
|
||||
|
||||
|
||||
//Misc patch definitions
|
||||
.string teddyremovetarget;
|
||||
|
||||
|
|
|
@ -1194,10 +1194,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.
|
||||
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
|
||||
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. */
|
||||
|
||||
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
|
||||
Retrives the number of bones in the model. The valid range is 1<=bone<=numbones. */
|
||||
|
||||
|
@ -1386,6 +1404,12 @@ string(string key) serverkey = #354; /*
|
|||
float(string key, optional float assumevalue) serverkeyfloat = #0:serverkeyfloat; /*
|
||||
Version of serverkey that returns the value as a float (which avoids tempstrings). */
|
||||
|
||||
|
||||
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
|
||||
Allocate an arbitary block of memory */
|
||||
|
||||
|
|
|
@ -98,6 +98,58 @@ void() StartFrame =
|
|||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Debugging IQM SSQC hitmeshes
|
||||
// ------------------------------------------------------------------------
|
||||
entity player = find(world, classname, "player");
|
||||
if(player != world) {
|
||||
vector player_pos = player.origin;
|
||||
vector player_angles = player.v_angle;
|
||||
makevectors(player_angles);
|
||||
vector view_ofs = '0 0 32';
|
||||
// traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, 0, player);
|
||||
// player.dimension_hit = 0;
|
||||
// traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, 4, player);
|
||||
traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, MOVE_HITMODEL, player); // 1<<2
|
||||
// traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, MOVE_EVERYTHING, player); // 1<<5
|
||||
// traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, MOVE_EVERYTHING | MOVE_HITMODEL, player); // 1<<5
|
||||
// traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, 0, player);
|
||||
player.dimension_hit |= HITBOX_DIM_ZOMBIES;
|
||||
// traceline(player_pos + view_ofs, player_pos + view_ofs + v_forward * 1000, MOVE_OTHERONLY | MOVE_HITMODEL, player);
|
||||
|
||||
// print("trace dist: ", ftos(1000 * trace_fraction), "\n");
|
||||
if(trace_ent.classname == "ai_zombie") {
|
||||
// entity zombie_ent = (AI_Chase) trace_ent;
|
||||
// TODO - Modify end limb state...
|
||||
switch(trace_surface_id) {
|
||||
case 1:
|
||||
print("Zombie body\n");
|
||||
break;
|
||||
case 2:
|
||||
print("Zombie head\n");
|
||||
break;
|
||||
case 3:
|
||||
print("Zombie left arm\n");
|
||||
break;
|
||||
case 4:
|
||||
print("Zombie left leg\n");
|
||||
break;
|
||||
case 5:
|
||||
print("Zombie right leg\n");
|
||||
break;
|
||||
case 6:
|
||||
print("Zombie right arm\n");
|
||||
break;
|
||||
default:
|
||||
// print("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (cl_navmesh_edit_mode) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,29 +12,6 @@ float(float a, float b) mod;
|
|||
float(float x) sign;
|
||||
float(float value, float minValue, float maxValue) wrap;
|
||||
|
||||
/*
|
||||
* clamp
|
||||
*
|
||||
* Limits the given value to the given range.
|
||||
*
|
||||
* value: A number
|
||||
*
|
||||
* minValue: The minimum value of the range
|
||||
*
|
||||
* maxValue: The maximum value of the range
|
||||
*
|
||||
* Returns: A number within the given range.
|
||||
*/
|
||||
float(float value, float minValue, float maxValue) clamp = {
|
||||
if (value < minValue) {
|
||||
return minValue;
|
||||
}
|
||||
else if (value > maxValue) {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/*
|
||||
* mod
|
||||
|
@ -125,12 +102,6 @@ float (vector ofs) vlen_xy = {
|
|||
}
|
||||
|
||||
|
||||
vector(vector a, vector b, float mix) lerpVector =
|
||||
{
|
||||
if (mix <= 0) return a;
|
||||
if (mix >= 1) return b;
|
||||
return (b * mix + a * ( 1 - mix ) );
|
||||
}
|
||||
|
||||
// for a relaxing lerp: hermite lerp.
|
||||
float(float a, float b, float mix) lerpHermite =
|
||||
|
|
|
@ -252,4 +252,40 @@ vector(vector a, vector b, float mix) lerp_vector {
|
|||
|
||||
vector lerp_vector_bezier(vector a, vector b, vector c, float mix) {
|
||||
return lerp_vector(lerp_vector(a,b,mix), lerp_vector(b,c,mix), mix);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* clamp
|
||||
*
|
||||
* Limits the given value to the given range.
|
||||
*
|
||||
* value: A number
|
||||
*
|
||||
* minValue: The minimum value of the range
|
||||
*
|
||||
* maxValue: The maximum value of the range
|
||||
*
|
||||
* Returns: A number within the given range.
|
||||
*/
|
||||
float(float value, float minValue, float maxValue) clamp = {
|
||||
if (value < minValue) {
|
||||
return minValue;
|
||||
}
|
||||
else if (value > maxValue) {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
vector(vector a, vector b, float mix) lerpVector =
|
||||
{
|
||||
if (mix <= 0) return a;
|
||||
if (mix >= 1) return b;
|
||||
return (b * mix + a * ( 1 - mix ) );
|
||||
}
|
||||
|
||||
|
||||
// Entity type identifiers when fields are synced from SSQC to CSQC
|
||||
// TODO - Generalize this to other AI_Chase types?
|
||||
#define ENT_TYPE_ZOMBIE 5
|
Loading…
Reference in a new issue