diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 63083f61..019d5456 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -3799,9 +3799,13 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu int numframes = 0; float duration = 0; qboolean loop = false; - if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop)) + int act = -1; + if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop, &act)) fname = "Unknown Sequence"; - Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f of %f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); + if (act != -1) + Draw_FunString(0, y, va("Frame%i[%i]: %s (%i poses, %f of %f secs, %s)", mods->framegroup, act, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); + else + Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f of %f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); y+=8; } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 6f692c38..c0490d1e 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -7054,8 +7054,9 @@ static struct { // {"skel_postmul_bones", PF_skel_postmul_bones, 0},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc) {"skel_copybones", PF_skel_copybones, 274},//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) {"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) - {"frameforname", PF_frameforname, 276},//void(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS) - {"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) + {"frameforname", PF_frameforname, 276},//float(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS) + {"frameduration", PF_frameduration, 277},//float(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) + {"frameforaction", PF_frameforaction, 0},//float(float modidx, string actionid) frameforaction = #0 {"processmodelevents", PF_processmodelevents, 0}, {"getnextmodelevent", PF_getnextmodelevent, 0}, {"getmodeleventidx", PF_getmodeleventidx, 0}, diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index 7a41c057..e8544469 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -903,7 +903,8 @@ void skel_generateragdoll_f(void) int numframes; float duration; qboolean loop; - if (!Mod_FrameInfoForNum(mod, 0, i, &fname, &numframes, &duration, &loop)) + int act; + if (!Mod_FrameInfoForNum(mod, 0, i, &fname, &numframes, &duration, &loop, &act)) break; VFS_PUTS(f, va("//%i %s (%i frames) (%f secs)%s", i, fname, numframes, duration, loop?" (loop)":"")); } @@ -2669,7 +2670,7 @@ void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_g void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { world_t *w = prinst->parms->user; - unsigned int modelindex = G_FLOAT(OFS_PARM0); + int modelindex = G_FLOAT(OFS_PARM0); unsigned int skinnum = G_FLOAT(OFS_PARM1); int surfaceidx = 0; model_t *mod = w->Get_CModel(w, modelindex); @@ -2684,7 +2685,7 @@ void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_g void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { world_t *w = prinst->parms->user; - unsigned int modelindex = G_FLOAT(OFS_PARM0); + int modelindex = G_FLOAT(OFS_PARM0); int surfaceidx = 0; const char *str = PF_VarString(prinst, 1, pr_globals); model_t *mod = w->Get_CModel(w, modelindex); @@ -2694,10 +2695,23 @@ void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_ else G_FLOAT(OFS_RETURN) = -1; } +void QCBUILTIN PF_frameforaction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + world_t *w = prinst->parms->user; + int modelindex = G_FLOAT(OFS_PARM0); + int surfaceidx = 0; + int actionid = G_INT(OFS_PARM1); + model_t *mod = w->Get_CModel(w, modelindex); + + if (mod) + G_FLOAT(OFS_RETURN) = Mod_FrameNumForAction(mod, surfaceidx, actionid); + else + G_FLOAT(OFS_RETURN) = -1; +} void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { world_t *w = prinst->parms->user; - unsigned int modelindex = G_FLOAT(OFS_PARM0); + int modelindex = G_FLOAT(OFS_PARM0); unsigned int framenum = G_FLOAT(OFS_PARM1); int surfaceidx = 0; model_t *mod = w->Get_CModel(w, modelindex); @@ -2723,7 +2737,7 @@ void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s * void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { world_t *w = prinst->parms->user; - unsigned int modelindex = G_FLOAT(OFS_PARM0); + int modelindex = G_FLOAT(OFS_PARM0); unsigned int frame = G_FLOAT(OFS_PARM1); float basetime = G_FLOAT(OFS_PARM2); float targettime = G_FLOAT(OFS_PARM3); @@ -2786,8 +2800,9 @@ void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_ char *data; float loopduration; qboolean looping; + int act; - if (Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping)) + if (Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping, &act)) { if (looping && loopduration) starttime = loopduration*(unsigned int)(basetime/loopduration); @@ -2891,8 +2906,9 @@ void QCBUILTIN PF_getnextmodelevent (pubprogfuncs_t *prinst, struct globalvars_s char *data; float loopduration; qboolean looping; + int act; - if (!Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping)) + if (!Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping, &act)) return; //invalid frame if (looping && loopduration) diff --git a/engine/client/render.h b/engine/client/render.h index a37fb576..12971523 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -555,6 +555,7 @@ void Mod_Shutdown (qboolean final); int Mod_TagNumForName(struct model_s *model, const char *name); int Mod_SkinNumForName(struct model_s *model, int surfaceidx, const char *name); int Mod_FrameNumForName(struct model_s *model, int surfaceidx, const char *name); +int Mod_FrameNumForAction(struct model_s *model, int surfaceidx, int actionid); float Mod_GetFrameDuration(struct model_s *model, int surfaceidx, int frameno); void Mod_ResortShaders(void); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index db7126b6..4a7ba839 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -2883,6 +2883,8 @@ typedef struct unsigned int posecount; float fps; qboolean loop; + int action; + int actionweight; char name[MAX_QPATH]; } frameinfo_t; static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups) @@ -2923,11 +2925,25 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups) frames[count].loop = true; else frames[count].loop = !!atoi(tok); + + frames[count].action = -1; + frames[count].actionweight = 0; + Q_snprintfz(frames[count].name, sizeof(frames[count].name), "groupified_%d_anim", count); //to match DP. frameforname cares. + line = COM_ParseType(line, tok, sizeof(tok), &ttype); if (ttype != TTP_EOF) + { Q_strncpyz(frames[count].name, tok, sizeof(frames[count].name)); - else - Q_snprintfz(frames[count].name, sizeof(frames[count].name), "groupified_%d_anim", count); //to match DP. frameforname cares. + line = COM_ParseType(line, tok, sizeof(tok), &ttype); + } + if (ttype != TTP_EOF) + { + frames[count].action = atoi(tok); + line = COM_ParseType(line, tok, sizeof(tok), &ttype); + } + if (ttype != TTP_EOF) + frames[count].actionweight = atoi(tok); + if (frames[count].posecount>0 && frames[count].fps) count++; @@ -3509,6 +3525,8 @@ static void *Q1MDL_LoadFrameGroup (galiasinfo_t *galias, dmdl_t *pq1inmodel, mod for (i = 0; i < pq1inmodel->numframes; i++) { + frame->action = -1; + frame->actionweight = 0; switch(LittleLong(pframetype->type)) { case ALIAS_SINGLE: @@ -3979,6 +3997,8 @@ static void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias) o->numposes = p; o->rate = framegroups[a].fps; o->loop = framegroups[a].loop; + o->action = -1; + o->actionweight = 0; Q_strncpyz(o->name, framegroups[a].name, sizeof(o->name)); } galias->numanimations = numanims; @@ -4981,6 +5001,8 @@ static qboolean QDECL Mod_LoadKingpinModel (model_t *mod, void *buffer, size_t f { poutframe->poseofs = pose; poutframe->numposes = 1; + poutframe->action = -1; + poutframe->actionweight = 0; galias->numanimations++; #ifndef SERVERONLY @@ -5490,6 +5512,47 @@ int Mod_FrameNumForName(model_t *model, int surfaceidx, const char *name) return -1; } +int Mod_FrameNumForAction(model_t *model, int surfaceidx, int actionid) +{ + galiasanimation_t *group; + galiasinfo_t *inf; + int i; + float weight; + + if (!model) + return -1; +#ifdef HALFLIFEMODELS + if (model->type == mod_halflife) + return HLMDL_FrameForAction(model, actionid); +#endif + if (model->type != mod_alias) + return -1; + + inf = Mod_Extradata(model); + + while(surfaceidx-->0 && inf) + inf = inf->nextsurf; + if (inf) + { + for (i = 0, weight = 0, group = inf->ofsanimations; i < inf->numanimations; i++, group++) + { + if (group->action == actionid) + weight += group->actionweight; + } + weight *= frandom(); + for (i = 0, group = inf->ofsanimations; i < inf->numanimations; i++, group++) + { + if (group->action == actionid) + { + if (weight <= group->actionweight) + return i; + weight -= group->actionweight; + } + } + } + return -1; +} + qboolean Mod_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata) { @@ -5586,7 +5649,7 @@ const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num) return NULL; } -qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop) +qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop, int *act) { galiasanimation_t *group; galiasinfo_t *inf; @@ -5615,11 +5678,12 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam *numframes = group[num].numposes; *loop = group[num].loop; *duration = group->numposes/group->rate; + *act = group[num].action; return true; } #ifdef HALFLIFEMODELS if (model->type == mod_halflife) - return HLMDL_FrameInfoForNum(model, surfaceidx, num, name, numframes, duration, loop); + return HLMDL_FrameInfoForNum(model, surfaceidx, num, name, numframes, duration, loop, act); #endif return false; } @@ -5766,7 +5830,8 @@ float Mod_GetFrameDuration(model_t *model, int surfaceidx, int frameno) float duration; char *name; qboolean loop; - HLMDL_FrameInfoForNum(model, surfaceidx, frameno, &name, &unused, &duration, &loop); + int act; + HLMDL_FrameInfoForNum(model, surfaceidx, frameno, &name, &unused, &duration, &loop, &act); return duration; } #endif @@ -6020,6 +6085,8 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff group->poseofs = pose + first; group->loop = framegroups[i].loop; group->events = NULL; + group->action = -1; + group->actionweight = 0; group++; } } @@ -6033,6 +6100,8 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff group->poseofs = pose + i; group->loop = false; group->events = NULL; + group->action = -1; + group->actionweight = 0; group++; } } @@ -6523,6 +6592,8 @@ static qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fs grp->loop = !(BigLong(inscene->flags) & ZYMSCENEFLAG_NOLOOP); grp->numposes = BigLong(inscene->length); grp->boneofs = matrix + BigLong(inscene->start)*12*root->numbones; + grp->action = -1; + grp->actionweight = 0; } if (inscene != (zymscene_t*)((char*)header + header->lump_scenes.start+header->lump_scenes.length)) @@ -7083,6 +7154,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) group[j].loop = frameinfo[j].loop; group[j].rate = frameinfo[j].fps; group[j].skeltype = SKEL_RELATIVE; + group[j].action = -1; + group[j].actionweight = 0; } num_animinfo = numgroups; } @@ -7107,6 +7180,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) group[iframe].loop = true; group[iframe].rate = animinfo[j].fps; group[iframe].skeltype = SKEL_RELATIVE; + group[iframe].action = -1; + group[iframe].actionweight = 0; iframe++; } } @@ -7126,6 +7201,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) group[i].loop = true; group[i].rate = animinfo[i].fps; group[i].skeltype = SKEL_RELATIVE; + group[i].action = -1; + group[i].actionweight = 0; } } for (j = 0; j < num_animkeys; j += num_boneinfo) @@ -7153,6 +7230,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize) group->loop = true; group->rate = 10; group->skeltype = SKEL_ABSOLUTE; + group->action = -1; + group->actionweight = 0; } @@ -7451,6 +7530,8 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t outgroups[i].numposes = 1; outgroups[i].skeltype = SKEL_RELATIVE; outgroups[i].boneofs = outposedata; + outgroups[i].action = -1; + outgroups[i].actionweight = 0; inposedata = (float*)((char*)buffer + inframes[i].ofs_bonepositions); for (j = 0; j < header->num_bones*12; j++) @@ -7488,6 +7569,8 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t outgroups[i].loop = framegroups[i].loop; outgroups[i].rate = framegroups[i].fps; outgroups[i].events = NULL; + outgroups[i].action = -1; + outgroups[i].actionweight = 0; Q_strncpyz(outgroups[i].name, framegroups[i].name, sizeof(outgroups[i].name)); } } @@ -8290,6 +8373,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz framegroups[i].posecount = LittleLong(anim[i].num_frames); framegroups[i].fps = LittleFloat(anim[i].framerate); framegroups[i].loop = !!(LittleLong(anim[i].flags) & IQM_LOOP); + framegroups[i].action = -1; + framegroups[i].actionweight = 0; Q_strncpyz(framegroups[i].name, strings+anim[i].name, sizeof(fgroup[i].name)); } } @@ -8303,6 +8388,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz framegroups->posecount = 1; framegroups->fps = 10; framegroups->loop = 1; + framegroups->action = -1; + framegroups->actionweight = 0; strcpy(framegroups->name, "base"); } @@ -8473,6 +8560,9 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz if (fgroup[i].rate <= 0) fgroup[i].rate = 10; + + fgroup[i].action = framegroups[i].action; + fgroup[i].actionweight = framegroups[i].actionweight; } free(framegroups); diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 9a27d1da..bdb25f58 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -62,6 +62,8 @@ typedef struct galiasanimation_s int numposes; //float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1] float rate; //average framerate of animation. + int action; + float actionweight; #ifdef NONSKELETALMODELS galiaspose_t *poseofs; #endif @@ -270,7 +272,7 @@ typedef struct modplugfuncs_s #define plugmodfuncs_name "Models_IDX" STRINGIFY(sizeof_index_t) #endif } plugmodfuncs_t; -#define MODPLUGFUNCS_VERSION 2 +#define MODPLUGFUNCS_VERSION 3 #ifdef SKELETALMODELS void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout); @@ -286,7 +288,7 @@ const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num); const char *Mod_SurfaceNameForNum(model_t *model, int num); const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num); const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num); -qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop); +qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop, int *act); qboolean Mod_DoCRC(model_t *mod, char *buffer, int buffersize); diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 2548e0b6..31448395 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -315,6 +315,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_ void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); + void QCBUILTIN PF_frameforaction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skinforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 6d3eb78f..2ac8dee4 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -612,6 +612,38 @@ int HLMDL_FrameForName(model_t *mod, const char *name) return -1; } +int HLMDL_FrameForAction(model_t *mod, int actionid) +{ + int i; + hlmdl_header_t *h; + hlmdl_sequencelist_t *seqs; + hlmodel_t *mc; + int weight = 0; + if (!mod || mod->type != mod_halflife) + return -1; //halflife models only, please + + mc = Mod_Extradata(mod); + + h = mc->header; + seqs = (hlmdl_sequencelist_t*)((char*)h+h->seqindex); + + //figure out the total weight. + for (i = 0; i < h->numseq; i++) + if (seqs[i].action == actionid) + weight += seqs[i].actionweight; + //pick a random number between 0 and the total weight... + weight *= frandom(); + //now figure out which sequence that gives us. + for (i = 0; i < h->numseq; i++) + if (seqs[i].action == actionid) + { + if (weight <= seqs[i].actionweight) + return i; + weight -= seqs[i].actionweight; + } + return -1; //failed... +} + qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata) { hlmodel_t *mc = Mod_Extradata(model); @@ -1146,7 +1178,7 @@ const char *HLMDL_FrameNameForNum(model_t *mod, int surfaceidx, int seqnum) ((unsigned int)seqnum>=model->header->numseq?0:seqnum); return sequence->name; } -qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **name, int *numframes, float *duration, qboolean *loop) +qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **name, int *numframes, float *duration, qboolean *loop, int *act) { hlmodel_t *model = Mod_Extradata(mod); hlmdl_sequencelist_t *sequence = (hlmdl_sequencelist_t *) ((qbyte *) model->header + model->header->seqindex) + @@ -1156,6 +1188,7 @@ qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char ** *numframes = sequence->numframes; *duration = (sequence->numframes-1)/sequence->timing; *loop = sequence->loop; + *act = sequence->action; return true; } diff --git a/engine/gl/model_hl.h b/engine/gl/model_hl.h index 47838667..04a2a4f3 100644 --- a/engine/gl/model_hl.h +++ b/engine/gl/model_hl.h @@ -224,7 +224,8 @@ typedef struct char name[32]; float timing; int loop; - int unknown1[2]; + int action; + int actionweight; int num_events; int ofs_events; int numframes; @@ -330,8 +331,9 @@ void *Mod_GetHalfLifeModelData(model_t *mod); //reflectioney things, including bone data int HLMDL_BoneForName(model_t *mod, const char *name); int HLMDL_FrameForName(model_t *mod, const char *name); +int HLMDL_FrameForAction(model_t *mod, int actionid); const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num); -qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop); +qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop, int *act); qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata); int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo); int HLMDL_GetBoneParent(model_t *mod, int bonenum); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 3bf69c91..5bf07923 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -11407,6 +11407,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"skel_delete", PF_skel_delete, 0, 0, 0, 275, D("void(float skel)", "Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object.")}, // (FTE_CSQC_SKELETONOBJECTS) {"frameforname", PF_frameforname, 0, 0, 0, 276, D("float(float modidx, string framename)", "Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error.")},// (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS) + {"frameforaction", PF_frameforaction, 0, 0, 0, 0, D("float(float modidx, int actionid)", "Returns a random frame/animation for the specified mod-defined action, or -1 if no animations have the specified action.")}, {"processmodelevents",PF_processmodelevents,0, 0, 0, 0, D("void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback)", "Calls a callback for each event that has been reached. Basetime is set to targettime.")}, {"getnextmodelevent",PF_getnextmodelevent,0, 0, 0, 0, D("float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data)", "Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime).\nWARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported).")}, {"getmodeleventidx",PF_getmodeleventidx,0, 0, 0, 0, D("float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data)", "Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp.")}, diff --git a/plugins/models/gltf.c b/plugins/models/gltf.c index 53d32d4e..22a7a572 100644 --- a/plugins/models/gltf.c +++ b/plugins/models/gltf.c @@ -3428,6 +3428,8 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize, } fg->loop = !!mod_gltf_loop->ival; fg->skeltype = SKEL_RELATIVE; + fg->action = -1; + fg->actionweight = 0; for(chan = JSON_FindIndexedChild(anim, "channels", 0); chan; chan = chan->sibling) { struct gltf_animsampler s;