set sv_jumpspeedcap_min "" "lower bound on the baseline velocity of a jump; final velocity will be >= (jumpheight * min + jumpheight)"
set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
-set sv_player_jumpanim_minfall 48 "minimum distance player has to have below their feet before the jump animation will be activated (only when falling, +jump will play anim instantly)"
seta sv_precacheplayermodels 1
seta sv_precacheweapons 0
seta scoreboard_border_thickness 1 "scoreboard border thickness"
seta scoreboard_accuracy_border_thickness 1 "accuracy stats border thickness"
seta scoreboard_accuracy_doublerows 0 "use two rows instead of one"
+seta scoreboard_accuracy_nocolors 0 "don't use colors displaying accuracy stats"
seta scoreboard_accuracy 1 "show weapon accuracy stats panel on scoreboard; colors can be configured with accuracy_color* cvars"
seta scoreboard_color_bg_r 0 "red color component of the scoreboard background"
seta scoreboard_color_bg_g 0.4 "green color component of the scoreboard background"
WarpZone_Init();
+ hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
hud_configure_prev = -1;
tab_panel = -1;
void CSQC_common_hud(void)
{
- // do some accuracy var caching
- float i;
- if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS))
- {
- if(autocvar_accuracy_color_levels != acc_color_levels)
- {
- if(acc_color_levels)
- strunzone(acc_color_levels);
- acc_color_levels = strzone(autocvar_accuracy_color_levels);
- acc_levels = tokenize_console(acc_color_levels);
- if (acc_levels > MAX_ACCURACY_LEVELS)
- acc_levels = MAX_ACCURACY_LEVELS;
-
- for (i = 0; i < acc_levels; ++i)
- acc_lev[i] = stof(argv(i)) / 100.0;
- }
- // let know that acc_col[] needs to be loaded
- acc_col[0] = '-1 0 0';
- }
+ if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS))
+ Accuracy_LoadLevels();
HUD_Main(); // always run these functions for alpha checks
HUD_DrawScoreboard();
float autocvar_r_letterbox;
float autocvar_scoreboard_accuracy;
float autocvar_scoreboard_accuracy_doublerows;
+float autocvar_scoreboard_accuracy_nocolors;
float autocvar_scoreboard_alpha_bg;
var float autocvar_scoreboard_alpha_fg = 1.0;
var float autocvar_scoreboard_alpha_name = 0.9;
float autocvar_cl_precacheplayermodels;
float autocvar_cl_deathglow;
float autocvar_developer_csqcentities;
+float autocvar__animblend;
+float autocvar__animblend_fixbone;
float autocvar_g_jetpack_attenuation;
-void CSQCModel_Hook_PreDraw();
+void CSQCModel_Hook_PreDraw(float isplayer);
.float isplayermodel;
// FEATURE: fallback frames
.float csqcmodel_saveframe;
.float csqcmodel_saveframe2;
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
.float csqcmodel_saveframe3;
.float csqcmodel_saveframe4;
+#endif
.float csqcmodel_framecount;
#define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
{
self.frame = self.csqcmodel_saveframe;
self.frame2 = self.csqcmodel_saveframe2;
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
self.frame3 = self.csqcmodel_saveframe3;
self.frame4 = self.csqcmodel_saveframe4;
+#endif
}
void CSQCPlayer_FallbackFrame_PostUpdate(float isnew)
{
self.csqcmodel_saveframe = self.frame;
self.csqcmodel_saveframe2 = self.frame2;
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
self.csqcmodel_saveframe3 = self.frame3;
self.csqcmodel_saveframe4 = self.frame4;
+#endif
// hack for death animations: set their frametime to zero in case a
// player "pops in"
}
FIX_FRAMETIME(frame, frame1time)
FIX_FRAMETIME(frame2, frame2time)
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
FIX_FRAMETIME(frame3, frame3time)
FIX_FRAMETIME(frame4, frame4time)
+#endif
}
self.csqcmodel_isdead = IS_DEAD_FRAME(self.frame);
}
{
self.frame = CSQCPlayer_FallbackFrame(self.frame);
self.frame2 = CSQCPlayer_FallbackFrame(self.frame2);
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
self.frame3 = CSQCPlayer_FallbackFrame(self.frame3);
self.frame4 = CSQCPlayer_FallbackFrame(self.frame4);
+#endif
}
// FEATURE: auto tag_index
{
entity oldself = self;
self = self.tag_entity;
- CSQCModel_Hook_PreDraw();
+ CSQCModel_Hook_PreDraw((self.entnum >= 1 && self.entnum <= maxclients));
self = oldself;
}
float EF_DOUBLESIDED = 32768;
float EF_NOSELFSHADOW = 65536;
float EF_DYNAMICMODELLIGHT = 131072;
+float EF_RESTARTANIM_BIT = 1048576;
+float EF_TELEPORT_BIT = 2097152;
float MF_ROCKET = 1; // leave a trail
float MF_GRENADE = 2; // leave a trail
float MF_GIB = 4; // leave a trail
// general functions
.float csqcmodel_predraw_run;
-void CSQCModel_Hook_PreDraw()
+.float anim_frame;
+.float anim_frame1time;
+.float anim_frame2;
+.float anim_frame2time;
+.float anim_saveframe;
+.float anim_saveframe1time;
+.float anim_saveframe2;
+.float anim_saveframe2time;
+.float anim_prev_pmove_flags;
+void CSQCModel_Hook_PreDraw(float isplayer)
{
if(self.csqcmodel_predraw_run == framecount)
return;
CSQCPlayer_ForceModel_Apply(self.entnum == player_localnum + 1);
CSQCPlayer_GlowMod_Apply();
CSQCPlayer_LOD_Apply();
- CSQCPlayer_FallbackFrame_Apply();
+ if(!isplayer)
+ CSQCPlayer_FallbackFrame_Apply();
+ else
+ {
+ // we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
+ float doblend = autocvar__animblend;
+ float onground = 0;
+ if(self == csqcplayer)
+ {
+ if(self.pmove_flags & PMF_ONGROUND)
+ onground = 1;
+ self.anim_prev_pmove_flags = self.pmove_flags;
+ if(self.pmove_flags & PMF_DUCKED)
+ animdecide_setstate(self, self.anim_state | ANIMSTATE_DUCK, FALSE);
+ else if(self.anim_state & ANIMSTATE_DUCK)
+ animdecide_setstate(self, self.anim_state - ANIMSTATE_DUCK, FALSE);
+ }
+ else
+ {
+ traceline(self.origin + '0 0 1' * self.maxs_z, self.origin + '0 0 1' * (self.mins_z - 4), MOVE_NOMONSTERS, self);
+ if(trace_startsolid || trace_fraction < 1)
+ onground = 1;
+ }
+ animdecide_init(self);
+ animdecide_setimplicitstate(self, onground);
+ animdecide_setframes(self, doblend, anim_frame, anim_frame1time, anim_frame2, anim_frame2time);
+ float sf = 0;
+ if(self.anim_saveframe != self.anim_frame || self.anim_saveframe1time != self.anim_frame1time)
+ sf |= CSQCMODEL_PROPERTY_FRAME;
+ if(self.anim_saveframe2 != self.anim_frame2 || self.anim_saveframe2time != self.anim_frame2time)
+ sf |= CSQCMODEL_PROPERTY_FRAME2;
+ self.anim_saveframe = self.anim_frame;
+ self.anim_saveframe1time = self.anim_frame1time;
+ self.anim_saveframe2 = self.anim_frame2;
+ self.anim_saveframe2time = self.anim_frame2time;
+ if(sf)
+ {
+ CSQCModel_InterpolateAnimation_2To4_PreNote(sf | CSQCMODEL_PROPERTY_LERPFRAC);
+ self.lerpfrac = (doblend ? 0.5 : 0);
+ self.frame = self.anim_frame;
+ self.frame1time = self.anim_frame1time;
+ self.frame2 = self.anim_frame2;
+ self.frame2time = self.anim_frame2time;
+ CSQCModel_InterpolateAnimation_2To4_Note(sf | CSQCMODEL_PROPERTY_LERPFRAC, FALSE);
+ }
+ CSQCModel_InterpolateAnimation_2To4_Do();
+ if(doblend)
+ {
+ skeleton_from_frames(self);
+ }
+ else
+ {
+ free_skeleton_from_frames(self);
+ // just in case, clear these (we're animating in frame and frame3)
+ self.lerpfrac = 0;
+ self.lerpfrac4 = 0;
+ }
+ }
}
CSQCModel_AutoTagIndex_Apply();
CSQCModel_Effects_PreUpdate();
if(self.isplayermodel)
{
- CSQCPlayer_FallbackFrame_PreUpdate();
+ if(!isplayer)
+ CSQCPlayer_FallbackFrame_PreUpdate();
CSQCPlayer_ForceModel_PreUpdate();
}
}
if(self.isplayermodel)
{
CSQCPlayer_ForceModel_PostUpdate();
- CSQCPlayer_FallbackFrame_PostUpdate(isnew);
+ if(!isplayer)
+ CSQCPlayer_FallbackFrame_PostUpdate(isnew);
}
CSQCModel_Effects_PostUpdate();
}
// declarations
WEPSET_DECLARE_A(weapons_stat);
WEPSET_COPY_AS(weapons_stat);
- float i, f, a, j, factor;
- float screen_ar, center_x, center_y;
+ float i, f, a;
+ float screen_ar, center_x = 0, center_y;
float weapon_count, weapon_id;
float row, column, rows, columns;
float aspect = autocvar_hud_panel_weapons_aspect;
- float show_accuracy = false, panel_weapon_accuracy;
+ float panel_weapon_accuracy;
float timeout = autocvar_hud_panel_weapons_timeout;
float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
{
if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
return;
- else if(timeout && time >= weapontime + timeout + timeout_effect_length && ((autocvar_hud_panel_weapons_timeout_effect != 1) && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
+ if(timeout && time >= weapontime + timeout + timeout_effect_length)
+ if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
{
weaponprevtime = time;
return;
else //top
panel_pos_y -= f * (panel_pos_y + panel_size_y);
}
+ if(f == 1)
+ center_x = -1; // mark the panel as off screen
}
weaponprevtime = time - (1 - f) * timein_effect_length;
}
// draw the background, then change the virtual size of it to better fit other items inside
HUD_Panel_DrawBg(1);
+
+ if(center_x == -1)
+ return;
+
if(panel_bg_padding)
{
panel_pos += '1 1 0' * panel_bg_padding;
baroffset_y = (weapon_size_y - barsize_y) / 2;
}
}
-
- if(autocvar_hud_panel_weapons_accuracy && acc_levels)
- {
- show_accuracy = true;
- if (acc_col[0] == '-1 0 0')
- for (i = 0; i < acc_levels; ++i)
- acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
- }
+ if(autocvar_hud_panel_weapons_accuracy)
+ Accuracy_LoadColors();
row = column = 0;
for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
drawpic_aspect_skin(weapon_pos, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
// draw the weapon accuracy
- if(show_accuracy)
+ if(autocvar_hud_panel_weapons_accuracy)
{
panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
if(panel_weapon_accuracy >= 0)
{
- // find the max level lower than weapon_accuracy
- j = acc_levels-1;
- while ( j && panel_weapon_accuracy < acc_lev[j] )
- --j;
-
- // inject color j+1 in color j, how much depending on how much weapon_accuracy is higher than level j
- factor = (panel_weapon_accuracy - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]);
- color = acc_col[j];
- color = color + factor * (acc_col[j+1] - color);
-
+ color = Accuracy_GetColor(panel_weapon_accuracy);
drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
}
}
return;
// Drawing stuff
- if (hud_skin_path != autocvar_hud_skin)
+ if (hud_skin_prev != autocvar_hud_skin)
{
if (hud_skin_path)
strunzone(hud_skin_path);
hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
+ if (hud_skin_prev)
+ strunzone(hud_skin_prev);
+ hud_skin_prev = strzone(autocvar_hud_skin);
}
// HUD configure visible grid
HUD_Panel_UpdatePosSizeForId(highlightedPanel);
HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha));
}
- if (!hud_configure_prev)
+ if(!hud_configure_prev || hud_configure_prev == -1)
{
if(autocvar_hud_cursormode) { setcursormode(1); }
hudShiftState = 0;
float scoreboard_bottom;
float weapon_accuracy[WEP_MAXCOUNT];
-#define MAX_ACCURACY_LEVELS 10
-float acc_lev[MAX_ACCURACY_LEVELS];
-vector acc_col[MAX_ACCURACY_LEVELS];
-float acc_levels;
-string acc_color_levels;
-
float complain_weapon;
string complain_weapon_name;
float complain_weapon_type;
float hud_fade_alpha;
string hud_skin_path;
+string hud_skin_prev;
var vector progressbar_color;
HUD_Write_PanelCvar_q("_freezetag_layout");
break;
case HUD_PANEL_PRESSEDKEYS:
- HUD_Write_PanelCvar_q("_attack");
HUD_Write_PanelCvar_q("_aspect");
+ HUD_Write_PanelCvar_q("_attack");
break;
case HUD_PANEL_ENGINEINFO:
HUD_Write_PanelCvar_q("_framecounter_time");
{
drawfont = FONT_USER+1;
}
+
+
+#define MAX_ACCURACY_LEVELS 10
+float acc_lev[MAX_ACCURACY_LEVELS];
+vector acc_col[MAX_ACCURACY_LEVELS];
+float acc_col_loadtime;
+float acc_levels;
+string acc_color_levels;
+void Accuracy_LoadLevels()
+{
+ float i;
+ if(autocvar_accuracy_color_levels != acc_color_levels)
+ {
+ if(acc_color_levels)
+ strunzone(acc_color_levels);
+ acc_color_levels = strzone(autocvar_accuracy_color_levels);
+ acc_levels = tokenize_console(acc_color_levels);
+ if(acc_levels > MAX_ACCURACY_LEVELS)
+ acc_levels = MAX_ACCURACY_LEVELS;
+ if(acc_levels < 2)
+ print("Warning: accuracy_color_levels must contain at least 2 values\n");
+
+ for(i = 0; i < acc_levels; ++i)
+ acc_lev[i] = stof(argv(i)) / 100.0;
+ }
+}
+
+void Accuracy_LoadColors()
+{
+ float i;
+ if(time > acc_col_loadtime)
+ if(acc_levels >= 2)
+ {
+ for(i = 0; i < acc_levels; ++i)
+ acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
+ acc_col_loadtime = time + 2;
+ }
+}
+
+vector Accuracy_GetColor(float accuracy)
+{
+ float j, factor;
+ vector color;
+ if(acc_levels < 2)
+ return '0 0 0'; // return black, can't determine the right color
+
+ // find the max level lower than acc
+ j = acc_levels-1;
+ while(j && accuracy < acc_lev[j])
+ --j;
+
+ // inject color j+1 in color j, how much depending on how much accuracy is higher than level j
+ factor = (accuracy - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]);
+ color = acc_col[j];
+ color = color + factor * (acc_col[j+1] - color);
+ return color;
+}
+
--- /dev/null
+.float skeleton_modelindex;
+#define BONETYPE_LOWER 0
+#define BONETYPE_UPPER 1
+#define MAX_BONES 128
+.float skeleton_bonetype[MAX_BONES];
+.float skeleton_fixrotatebone;
+.float skeleton_fixtargetbone;
+.float skeleton_bone;
+.float skeleton_aimbone;
+.float skeleton_numbones;
+
+void skeleton_identifybones(entity e)
+{
+ float s = e.skeletonindex;
+ float n = (e.skeleton_numbones = skel_get_numbones(s));
+ e.skeleton_aimbone = 0;
+ e.skeleton_fixrotatebone = 0;
+ e.skeleton_fixtargetbone = 0;
+ float i;
+ for(i = 1; i <= n; ++i)
+ {
+ float t = BONETYPE_LOWER;
+ float p = skel_get_boneparent(s, i);
+ if(p > 0)
+ t = e.(skeleton_bonetype[p-1]);
+ string nm = skel_get_bonename(s, i);
+ if(nm == "spine2")
+ {
+ e.skeleton_fixrotatebone = i;
+ t = BONETYPE_UPPER;
+ }
+ if(nm == "weapon" || nm == "tag_weapon" || nm == "bip01 r hand")
+ if(t == BONETYPE_UPPER)
+ e.skeleton_fixtargetbone = i;
+ if(nm == "upperarm_R")
+ e.skeleton_aimbone = i;
+ e.(skeleton_bonetype[i-1]) = t;
+ }
+}
+
+void skel_set_bone_lerp(float skel, float bone, vector org, float strength)
+{
+ if(strength >= 1)
+ return skel_set_bone(skel, bone, org);
+
+ vector fo = v_forward;
+ vector ri = v_right;
+ vector up = v_up;
+ vector oldorg = skel_get_bonerel(skel, bone);
+
+ org = org * strength + oldorg * (1 - strength);
+ v_forward = fo * strength + v_forward * (1 - strength);
+ v_right = ri * strength + v_right * (1 - strength);
+ v_up = up * strength + v_up * (1 - strength);
+ return skel_set_bone(skel, bone, org);
+}
+
+void skeleton_fixbone(entity e, float strength, float yawonly)
+{
+ if(!e.skeleton_fixrotatebone)
+ return;
+ if(strength <= 0)
+ return;
+ // model:
+ // T = M_before_fixrotate * M_fixrotate * M_after_fixrotate
+ // T' = M_before_fixrotate^-1 * M_fixrotate' * M_after_fixrotate
+ // M_fixrotate' = M_before_fixrotate^-1 * T' * M_after_fixrotate^-1
+ float s = e.skeletonindex;
+
+ skel_get_boneabs(s, skel_get_boneparent(s, e.skeleton_fixrotatebone));
+ vector M_before_fixrotate = fixedvectoangles2(v_forward, v_up);
+ skel_get_boneabs(s, e.skeleton_fixrotatebone);
+ vector M_including_fixrotate = fixedvectoangles2(v_forward, v_up);
+ skel_get_boneabs(s, e.skeleton_fixtargetbone);
+ vector T = fixedvectoangles2(v_forward, v_up);
+ vector M_after_fixrotate = AnglesTransform_LeftDivide(M_including_fixrotate, T);
+ vector T_ = T;
+ if(yawonly)
+ T__y = 0; // undo yaw
+ else
+ T_ = '0 0 0'; // undo all
+ vector M_fixrotate_ = AnglesTransform_LeftDivide(M_before_fixrotate, AnglesTransform_RightDivide(T_, M_after_fixrotate));
+ vector org = skel_get_bonerel(s, e.skeleton_fixrotatebone);
+ fixedmakevectors(M_fixrotate_);
+ skel_set_bone_lerp(s, e.skeleton_fixrotatebone, org, strength);
+}
+
+void free_skeleton_from_frames(entity e)
+{
+ if(e.skeletonindex)
+ {
+ skel_delete(e.skeletonindex);
+ e.skeletonindex = 0;
+ }
+}
+
+void skeleton_from_frames(entity e)
+{
+ float m = e.modelindex;
+ if(m != e.skeleton_modelindex)
+ {
+ if(e.skeletonindex)
+ {
+ skel_delete(e.skeletonindex);
+ e.skeletonindex = 0;
+ }
+ m = (e.skeleton_modelindex = e.modelindex);
+ if(m)
+ {
+ e.skeletonindex = skel_create(m);
+ skeleton_identifybones(e);
+ }
+ }
+ float s = e.skeletonindex;
+ if(!s)
+ return;
+ float bone;
+ float n = e.skeleton_numbones;
+ float savelerpfrac = e.lerpfrac;
+ float savelerpfrac3 = e.lerpfrac3;
+ float savelerpfrac4 = e.lerpfrac4;
+ for(bone = 0; bone < n; )
+ {
+ float firstbone = bone;
+ float bonetype = e.skeleton_bonetype[bone];
+ for(++bone; (bone < n) && (e.skeleton_bonetype[bone] == bonetype); ++bone)
+ ;
+ if(bonetype == BONETYPE_UPPER)
+ {
+ // only show frames 1+3 (upper body)
+ e.lerpfrac = 0;
+ e.lerpfrac3 = savelerpfrac3 * 2;
+ e.lerpfrac4 = 0;
+ }
+ else
+ {
+ // only show frames 2+4 (lower body)
+ e.lerpfrac = savelerpfrac * 2;
+ e.lerpfrac3 = 0;
+ e.lerpfrac4 = savelerpfrac4 * 2;
+ }
+ //print(sprintf("Run: bone %d to %d, type %d\n", firstbone + 1, bone, bonetype));
+ //print(sprintf("frame %d %d %d %d lerpfrac * %d %d %d\n", e.frame, e.frame2, e.frame3, e.frame4, e.lerpfrac, e.lerpfrac3, e.lerpfrac4));
+ skel_build(s, e, m, 0, firstbone + 1, bone);
+ }
+ e.lerpfrac = savelerpfrac;
+ e.lerpfrac3 = savelerpfrac3;
+ e.lerpfrac4 = savelerpfrac4;
+
+ if(autocvar__animblend_fixbone)
+ {
+ float l4 = e.lerpfrac4;
+ float l3 = e.lerpfrac3;
+ float l2 = e.lerpfrac;
+ float l1 = 1 - l2 - l3 - l4;
+
+ // how much of upper body animates same way as lower body?
+ float equalamount =
+ (e.frame == e.frame2) * (l1 * l2) +
+ (e.frame == e.frame4) * (l1 * l4) +
+ (e.frame3 == e.frame2) * (l3 * l2) +
+ (e.frame3 == e.frame4) * (l3 * l4);
+ float maxequalamount = (l1 + l3) * (l2 + l4);
+
+ // now how strong is the lerp?
+ float lerpstrength = 1 - equalamount / maxequalamount;
+
+ // FIX IT
+ skeleton_fixbone(e, lerpstrength, autocvar__animblend_fixbone >= 2);
+ }
+}
--- /dev/null
+void free_skeleton_from_frames(entity e);
+void skeleton_from_frames(entity e);
../common/command/generic.qh
../common/command/shared_defs.qh
../common/urllib.qh
+../common/animdecide.qh
command/cl_cmd.qh
autocvars.qh
../csqcmodellib/cl_model.qh
../csqcmodellib/cl_player.qh
projectile.qh
+player_skeleton.qh
sortlist.qc
miscfunctions.qc
../warpzonelib/client.qc
tturrets.qc
+player_skeleton.qc
+../common/animdecide.qc
+
../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
g_minstagib = 1; // TODO: real detection for minstagib?
float weapon_stats;
-
- if (!acc_levels)
+ if(autocvar_scoreboard_accuracy_nocolors)
rgb = '1 1 1';
- else if (acc_col[0] == '-1 0 0')
- for (i = 0; i < acc_levels; ++i)
- acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
+ else
+ Accuracy_LoadColors();
for(i = WEP_FIRST; i <= WEP_LAST; ++i)
{
float padding;
padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
- if (acc_levels)
- {
- // find the max level lower than weapon_stats
- float j;
- j = acc_levels-1;
- while ( j && weapon_stats < acc_lev[j] )
- --j;
-
- // inject color j+1 in color j, how much depending on how much weapon_stats is higher than level j
- float factor;
- factor = (weapon_stats - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]);
- rgb = acc_col[j];
- rgb = rgb + factor * (acc_col[j+1] - rgb);
- }
+ if(!autocvar_scoreboard_accuracy_nocolors)
+ rgb = Accuracy_GetColor(weapon_stats);
drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
}
}
if(weapons_with_stats)
- average_accuracy = floor(average_accuracy / weapons_with_stats);
+ average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
if(rows == 2)
pos_x -= weapon_width / 2;
--- /dev/null
+// player animation data for this model
+// each vector is as follows:
+// _x = startframe
+// _y = numframes
+// _z = framerate
+.vector anim_die1; // player dies
+.vector anim_die2; // player dies differently
+.vector anim_draw; // player pulls out a weapon
+.vector anim_duckwalk; // player walking while crouching
+.vector anim_duckjump; // player jumping from a crouch
+.vector anim_duckidle; // player idling while crouching
+.vector anim_idle; // player standing
+.vector anim_jump; // player jump
+.vector anim_pain1; // player flinches from pain
+.vector anim_pain2; // player flinches from pain, differently
+.vector anim_shoot; // player shoots
+.vector anim_taunt; // player taunts others (FIXME: no code references this)
+.vector anim_run; // player running forward
+.vector anim_runbackwards; // player running backward
+.vector anim_strafeleft; // player shuffling left quickly
+.vector anim_straferight; // player shuffling right quickly
+.vector anim_forwardright; // player running forward and right
+.vector anim_forwardleft; // player running forward and left
+.vector anim_backright; // player running backward and right
+.vector anim_backleft; // player running back and left
+.vector anim_melee; // player doing the melee action
+.vector anim_duck; // player doing the melee action
+.vector anim_duckwalkbackwards;
+.vector anim_duckwalkstrafeleft;
+.vector anim_duckwalkstraferight;
+.vector anim_duckwalkforwardright;
+.vector anim_duckwalkforwardleft;
+.vector anim_duckwalkbackright;
+.vector anim_duckwalkbackleft;
+.float animdecide_modelindex;
+
+void animdecide_init(entity e)
+{
+ if(e.modelindex == e.animdecide_modelindex)
+ return;
+ e.animdecide_modelindex = e.modelindex;
+
+ vector none = '0 0 0';
+ e.anim_die1 = animfixfps(e, '0 1 0.5', none); // 2 seconds
+ e.anim_die2 = animfixfps(e, '1 1 0.5', none); // 2 seconds
+ e.anim_draw = animfixfps(e, '2 1 3', none);
+ e.anim_duckwalk = animfixfps(e, '4 1 1', none);
+ e.anim_duckjump = animfixfps(e, '5 1 10', none);
+ e.anim_duckidle = animfixfps(e, '6 1 1', none);
+ e.anim_idle = animfixfps(e, '7 1 1', none);
+ e.anim_jump = animfixfps(e, '8 1 10', none);
+ e.anim_pain1 = animfixfps(e, '9 1 2', none); // 0.5 seconds
+ e.anim_pain2 = animfixfps(e, '10 1 2', none); // 0.5 seconds
+ e.anim_shoot = animfixfps(e, '11 1 5', none); // analyze models and set framerate
+ e.anim_taunt = animfixfps(e, '12 1 0.33', none);
+ e.anim_run = animfixfps(e, '13 1 1', none);
+ e.anim_runbackwards = animfixfps(e, '14 1 1', none);
+ e.anim_strafeleft = animfixfps(e, '15 1 1', none);
+ e.anim_straferight = animfixfps(e, '16 1 1', none);
+ e.anim_forwardright = animfixfps(e, '19 1 1', '16 1 1');
+ e.anim_forwardleft = animfixfps(e, '20 1 1', '15 1 1');
+ e.anim_backright = animfixfps(e, '21 1 1', '16 1 1');
+ e.anim_backleft = animfixfps(e, '22 1 1', '15 1 1');
+ e.anim_melee = animfixfps(e, '23 1 1', '11 1 1');
+ e.anim_duckwalkbackwards = animfixfps(e, '24 1 1', '4 1 1');
+ e.anim_duckwalkstrafeleft = animfixfps(e, '25 1 1', '4 1 1');
+ e.anim_duckwalkstraferight = animfixfps(e, '26 1 1', '4 1 1');
+ e.anim_duckwalkforwardright = animfixfps(e, '27 1 1', '4 1 1');
+ e.anim_duckwalkforwardleft = animfixfps(e, '28 1 1', '4 1 1');
+ e.anim_duckwalkbackright = animfixfps(e, '29 1 1', '4 1 1');
+ e.anim_duckwalkbackleft = animfixfps(e, '30 1 1', '4 1 1');
+
+ // these anims ought to stay until stopped explicitly by weaponsystem
+ e.anim_shoot_z = 0.001;
+ e.anim_melee_z = 0.001;
+}
+
+#define ANIMPRIO_IDLE 0
+#define ANIMPRIO_ACTIVE 1
+#define ANIMPRIO_CROUCH 2
+#define ANIMPRIO_DEAD 3
+
+vector animdecide_getupperanim(entity e)
+{
+ // death etc.
+ if(e.anim_state & ANIMSTATE_FROZEN)
+ return vec3(e.anim_idle_x, e.anim_time, ANIMPRIO_DEAD);
+ if(e.anim_state & ANIMSTATE_DEAD1)
+ return vec3(e.anim_die1_x, e.anim_time, ANIMPRIO_DEAD);
+ if(e.anim_state & ANIMSTATE_DEAD2)
+ return vec3(e.anim_die2_x, e.anim_time, ANIMPRIO_DEAD);
+
+ // is there an action?
+ vector outframe = '-1 0 0';
+ float t, a;
+ if(e.anim_upper_time >= e.anim_upper_implicit_time)
+ {
+ a = e.anim_upper_action;
+ t = e.anim_upper_time;
+ }
+ else
+ {
+ a = e.anim_upper_implicit_action;
+ t = e.anim_upper_implicit_time;
+ }
+ switch(a)
+ {
+ case ANIMACTION_DRAW: outframe = e.anim_draw; break;
+ case ANIMACTION_PAIN1: outframe = e.anim_pain1; break;
+ case ANIMACTION_PAIN2: outframe = e.anim_pain2; break;
+ case ANIMACTION_SHOOT: outframe = e.anim_shoot; break;
+ case ANIMACTION_TAUNT: outframe = e.anim_taunt; break;
+ case ANIMACTION_MELEE: outframe = e.anim_melee; break;
+ }
+ if(outframe_x >= 0)
+ {
+ if(time <= t + outframe_y / outframe_z)
+ {
+ // animation is running!
+ return vec3(outframe_x, t, ANIMPRIO_ACTIVE);
+ }
+ }
+ // or, decide the anim by state
+ t = max(e.anim_time, e.anim_implicit_time);
+ // but all states are for lower body!
+ return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE);
+}
+
+vector animdecide_getloweranim(entity e)
+{
+ // death etc.
+ if(e.anim_state & ANIMSTATE_FROZEN)
+ return vec3(e.anim_idle_x, e.anim_time, ANIMPRIO_DEAD);
+ if(e.anim_state & ANIMSTATE_DEAD1)
+ return vec3(e.anim_die1_x, e.anim_time, ANIMPRIO_DEAD);
+ if(e.anim_state & ANIMSTATE_DEAD2)
+ return vec3(e.anim_die2_x, e.anim_time, ANIMPRIO_DEAD);
+
+ // is there an action?
+ vector outframe = '-1 0 0';
+ float t, a;
+ if(e.anim_lower_time >= e.anim_lower_implicit_time)
+ {
+ a = e.anim_lower_action;
+ t = e.anim_lower_time;
+ }
+ else
+ {
+ a = e.anim_lower_implicit_action;
+ t = e.anim_lower_implicit_time;
+ }
+ switch(a)
+ {
+ case ANIMACTION_JUMP: if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR) { if(e.anim_state & ANIMSTATE_DUCK) outframe = e.anim_duckjump; else outframe = e.anim_jump; } break;
+ }
+ if(outframe_x >= 0)
+ {
+ if(time <= t + outframe_y / outframe_z)
+ {
+ // animation is running!
+ return vec3(outframe_x, t, ANIMPRIO_ACTIVE);
+ }
+ }
+ // or, decide the anim by state
+ t = max(e.anim_time, e.anim_implicit_time);
+ if(e.anim_state & ANIMSTATE_DUCK)
+ {
+ if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR)
+ return vec3(e.anim_duckjump_x, 0, ANIMPRIO_CROUCH); // play the END of the jump anim
+ else switch(e.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT))
+ {
+ case ANIMIMPLICITSTATE_FORWARD:
+ return vec3(e.anim_duckwalk_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_BACKWARDS:
+ return vec3(e.anim_duckwalkbackwards_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_RIGHT:
+ return vec3(e.anim_duckwalkstraferight_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_LEFT:
+ return vec3(e.anim_duckwalkstrafeleft_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT:
+ return vec3(e.anim_duckwalkforwardright_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT:
+ return vec3(e.anim_duckwalkforwardleft_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT:
+ return vec3(e.anim_duckwalkbackright_x, t, ANIMPRIO_CROUCH);
+ case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT:
+ return vec3(e.anim_duckwalkbackleft_x, t, ANIMPRIO_CROUCH);
+ default:
+ return vec3(e.anim_duckidle_x, t, ANIMPRIO_CROUCH);
+ }
+ }
+ else
+ {
+ if(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR)
+ return vec3(e.anim_jump_x, 0, ANIMPRIO_ACTIVE); // play the END of the jump anim
+ else switch(e.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT))
+ {
+ case ANIMIMPLICITSTATE_FORWARD:
+ return vec3(e.anim_run_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_BACKWARDS:
+ return vec3(e.anim_runbackwards_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_RIGHT:
+ return vec3(e.anim_straferight_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_LEFT:
+ return vec3(e.anim_strafeleft_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT:
+ return vec3(e.anim_forwardright_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT:
+ return vec3(e.anim_forwardleft_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT:
+ return vec3(e.anim_backright_x, t, ANIMPRIO_ACTIVE);
+ case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT:
+ return vec3(e.anim_backleft_x, t, ANIMPRIO_ACTIVE);
+ default:
+ return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE);
+ }
+ }
+ // can't get here
+#ifdef GMQCC
+ return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE);
+#endif
+}
+
+void animdecide_setimplicitstate(entity e, float onground)
+{
+ float s;
+ s = 0;
+
+ makevectors(e.angles);
+ vector v;
+ v_x = e.velocity * v_forward;
+ v_y = e.velocity * v_right;
+ v_z = 0;
+
+ // we want to match like this:
+ // the 8 directions shall be "evenly spaced"
+ // that means, the forward key includes anything from -67.5 to +67.5 degrees
+ // which then means x > |y| * cot(3pi/8)
+ //
+ // BUT, the engine's clip-movement-to-keyboard function uses 0.5 here,
+ // which would be an angle range from -63.43 to +63.43 degrees, making
+ // it slightly less likely to "hit two keys at once", so let's do this
+ // here too
+
+ if(vlen(v) > 10)
+ {
+ if(v_x > fabs(v_y) * 0.5)
+ s |= ANIMIMPLICITSTATE_FORWARD;
+ if(v_x < -fabs(v_y) * 0.5)
+ s |= ANIMIMPLICITSTATE_BACKWARDS;
+ if(v_y > fabs(v_x) * 0.5)
+ s |= ANIMIMPLICITSTATE_RIGHT;
+ if(v_y < -fabs(v_x) * 0.5)
+ s |= ANIMIMPLICITSTATE_LEFT;
+ }
+ if(!onground)
+ s |= ANIMIMPLICITSTATE_INAIR;
+
+ // detect some kinds of otherwise misdetected jumps (ground to air transition)
+ // NOTE: currently, in CSQC this is the only jump detection, as the explicit jump action is never called!
+ if(!(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR) && (s & ANIMIMPLICITSTATE_INAIR))
+ {
+ e.anim_lower_implicit_action = ANIMACTION_JUMP;
+ e.anim_lower_implicit_time = time;
+ }
+
+ if(s != e.anim_implicit_state)
+ {
+ e.anim_implicit_state = s;
+ e.anim_implicit_time = time;
+ }
+}
+void animdecide_setframes(entity e, float support_blending, .float fld_frame, .float fld_frame1time, .float fld_frame2, .float fld_frame2time)
+{
+ // _x: frame
+ // _y: start time
+ // _z: priority
+ vector upper = animdecide_getupperanim(e);
+ vector lower = animdecide_getloweranim(e);
+ //print("UPPER: ", vtos(upper), ", LOWER: ", vtos(lower), "\n");
+ if(support_blending)
+ {
+ if(upper_z && !lower_z)
+ lower = upper;
+ else if(lower_z && !upper_z)
+ upper = lower;
+ if(e.frame1time != upper_y || e.frame2time != lower_y)
+ BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
+ e.fld_frame = upper_x;
+ e.fld_frame1time = upper_y;
+ e.fld_frame2 = lower_x;
+ e.fld_frame2time = lower_y;
+ }
+ else
+ {
+ if(upper_z > lower_z)
+ lower = upper;
+ else if(lower_z > upper_z)
+ upper = lower;
+ if(e.frame1time != upper_y)
+ BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
+ e.fld_frame = upper_x;
+ e.fld_frame1time = upper_y;
+ }
+}
+
+void animdecide_setstate(entity e, float newstate, float restart)
+{
+ if(!restart)
+ if(newstate == e.anim_state)
+ return;
+ e.anim_state = newstate;
+ e.anim_time = time;
+}
+void animdecide_setaction(entity e, float action, float restart)
+{
+ if(action < 0)
+ {
+ if(!restart)
+ if(action == e.anim_lower_action)
+ return;
+ e.anim_lower_action = action;
+ e.anim_lower_time = time;
+ }
+ else
+ {
+ if(!restart)
+ if(action == e.anim_upper_action)
+ return;
+ e.anim_upper_action = action;
+ e.anim_upper_time = time;
+ }
+}
--- /dev/null
+// client side frame inferring
+void animdecide_init(entity e);
+
+void animdecide_setimplicitstate(entity e, float onground);
+void animdecide_setframes(entity e, float support_blending, .float fld_frame, .float fld_frame1time, .float fld_frame2, .float fld_frame2time);
+
+// please network this one
+.float anim_state;
+.float anim_time;
+.float anim_lower_action;
+.float anim_lower_time;
+.float anim_upper_action;
+.float anim_upper_time;
+
+// when copying entities, copy these too
+.float anim_implicit_state;
+.float anim_implicit_time;
+.float anim_lower_implicit_action;
+.float anim_lower_implicit_time;
+.float anim_upper_implicit_action;
+.float anim_upper_implicit_time;
+
+// explicit anim states (networked)
+void animdecide_setstate(entity e, float newstate, float restart);
+#define ANIMSTATE_DEAD1 1 // base frames: die1
+#define ANIMSTATE_DEAD2 2 // base frames: die2
+#define ANIMSTATE_DUCK 4 // turns walk into duckwalk, jump into duckjump, etc.
+#define ANIMSTATE_FROZEN 8 // force idle
+
+// implicit anim states (inferred from velocity, etc.)
+#define ANIMIMPLICITSTATE_INAIR 1
+#define ANIMIMPLICITSTATE_FORWARD 2
+#define ANIMIMPLICITSTATE_BACKWARDS 4
+#define ANIMIMPLICITSTATE_LEFT 8
+#define ANIMIMPLICITSTATE_RIGHT 16
+#define ANIMIMPLICITSTATE_JUMPRELEASED 32
+
+// explicit actions (networked); negative values are for lower body
+void animdecide_setaction(entity e, float action, float restart);
+#define ANIMACTION_JUMP -1 // jump
+#define ANIMACTION_DRAW 1 // draw
+#define ANIMACTION_PAIN1 2 // pain
+#define ANIMACTION_PAIN2 3 // pain
+#define ANIMACTION_SHOOT 4 // shoot
+#define ANIMACTION_TAUNT 5 // taunt
+#define ANIMACTION_MELEE 6 // melee
// define this if svqc code wants to use .frame2 and .lerpfrac
-#define CSQCMODEL_HAVE_TWO_FRAMES
+//#define CSQCMODEL_HAVE_TWO_FRAMES
// don't define this ever
//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+// server decides crouching, this lags, but so be it
+#define CSQCMODEL_SERVERSIDE_CROUCH
+
// a hack for Xonotic
#ifdef CSQC
# define TAG_ENTITY_NAME tag_networkentity
CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_x, 255, 0, 255) \
CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_y, 255, 0, 255) \
CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_z, 255, 0, 255) \
+ CSQCMODEL_ENDIF \
+ CSQCMODEL_IF(isplayer) \
+ CSQCMODEL_PROPERTY(128, float, ReadByte, WriteByte, anim_state) \
+ CSQCMODEL_PROPERTY(128, float, ReadApproxPastTime, WriteApproxPastTime, anim_time) \
+ CSQCMODEL_IF(!islocalplayer) \
+ CSQCMODEL_PROPERTY(256, float, ReadChar, WriteChar, anim_lower_action) \
+ CSQCMODEL_PROPERTY(256, float, ReadApproxPastTime, WriteApproxPastTime, anim_lower_time) \
+ CSQCMODEL_ENDIF \
+ CSQCMODEL_PROPERTY(512, float, ReadChar, WriteChar, anim_upper_action) \
+ CSQCMODEL_PROPERTY(512, float, ReadApproxPastTime, WriteApproxPastTime, anim_upper_time) \
CSQCMODEL_ENDIF
// TODO get rid of colormod/glowmod here, find good solution for nex charge glowmod hack; also get rid of some useless properties on non-players that only exist for CopyBody
#define CSQCMODEL_HOOK_POSTUPDATE \
CSQCModel_Hook_PostUpdate(isnew, isplayer, islocalplayer);
#define CSQCMODEL_HOOK_PREDRAW \
- CSQCModel_Hook_PreDraw();
+ CSQCModel_Hook_PreDraw(isplayer);
#define CSQCPLAYER_HOOK_POSTCAMERASETUP
// force updates of player entities that often even if unchanged
for(queue_start = e; queue_start; queue_start = queue_start.fld)
queue_start.FindConnectedComponent_processing = 0;
}
+
+vector vec3(float x, float y, float z)
+{
+ vector v;
+ v_x = x;
+ v_y = y;
+ v_z = z;
+ return v;
+}
+
+#ifndef MENUQC
+vector animfixfps(entity e, vector a, vector b)
+{
+ // multi-frame anim: keep as-is
+ if(a_y == 1)
+ {
+ float dur;
+ dur = frameduration(e.modelindex, a_x);
+ if(dur <= 0 && b_y)
+ {
+ a = b;
+ dur = frameduration(e.modelindex, a_x);
+ }
+ if(dur > 0)
+ a_z = 1.0 / dur;
+ }
+ return a;
+}
+#endif
typedef entity(entity cur, entity near, entity pass) findNextEntityNearFunction_t;
typedef float(entity a, entity b, entity pass) isConnectedFunction_t;
void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass);
+
+vector vec3(float x, float y, float z);
+
+#ifndef MENUQC
+vector animfixfps(entity e, vector a, vector b);
+#endif
.float csqcmodel_lerpfractime;
.float csqcmodel_lerpfrac2time;
-void CSQCModel_InterpolateAnimation_PreNote(float sf)
+void CSQCModel_InterpolateAnimation_2To4_PreNote(float sf)
{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
if(sf & CSQCMODEL_PROPERTY_FRAME)
{
self.frame3 = self.frame;
self.csqcmodel_lerpfrac2time = self.csqcmodel_lerpfractime;
self.lerpfrac = self.csqcmodel_lerpfrac;
}
-#else
+}
+void CSQCModel_InterpolateAnimation_1To2_PreNote(float sf)
+{
if(sf & CSQCMODEL_PROPERTY_FRAME)
{
self.frame2 = self.frame;
self.frame2time = self.frame1time;
}
+}
+void CSQCModel_InterpolateAnimation_PreNote(float sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+ CSQCModel_InterpolateAnimation_2To4_PreNote(sf);
+#else
+ CSQCModel_InterpolateAnimation_1To2_PreNote(sf);
#endif
}
-void CSQCModel_InterpolateAnimation_Note(float sf)
+void CSQCModel_InterpolateAnimation_2To4_Note(float sf, float set_times)
{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
if(sf & CSQCMODEL_PROPERTY_FRAME)
{
- self.frame1time = time;
+ if(set_times)
+ self.frame1time = time;
}
if(sf & CSQCMODEL_PROPERTY_FRAME2)
{
- self.frame2time = time;
+ if(set_times)
+ self.frame2time = time;
}
if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
{
self.csqcmodel_lerpfrac = self.lerpfrac;
- self.csqcmodel_lerpfractime = time;
+ if(set_times)
+ self.csqcmodel_lerpfractime = time;
}
-#else
+}
+void CSQCModel_InterpolateAnimation_1To2_Note(float sf, float set_times)
+{
if(sf & CSQCMODEL_PROPERTY_FRAME)
{
- self.frame1time = time;
+ if(set_times)
+ self.frame1time = time;
}
+}
+void CSQCModel_InterpolateAnimation_Note(float sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+ CSQCModel_InterpolateAnimation_2To4_Note(sf, TRUE);
+#else
+ CSQCModel_InterpolateAnimation_1To2_Note(sf, TRUE);
#endif
}
-void CSQCModel_InterpolateAnimation_Do()
+void CSQCModel_InterpolateAnimation_2To4_Do()
{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
{
self.lerpfrac = self.csqcmodel_lerpfrac;
self.frame3time = 0;
}
}
-#else
+}
+void CSQCModel_InterpolateAnimation_1To2_Do()
+{
if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
{
self.lerpfrac = 0;
else
self.lerpfrac = 1 - bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
}
+}
+void CSQCModel_InterpolateAnimation_Do()
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+ CSQCModel_InterpolateAnimation_2To4_Do();
+#else
+ CSQCModel_InterpolateAnimation_1To2_Do();
#endif
}
self.classname = "csqcmodel";
self.iflags |= IFLAG_ANGLES; // interpolate angles too
+ self.iflags |= IFLAG_VELOCITY | IFLAG_AUTOVELOCITY; // let's calculate velocity automatically
{ CSQCMODEL_HOOK_PREUPDATE }
entity CSQCModel_server2csqc(float pl);
.float csqcmodel_teleported;
+
+// this is exported for custom frame animation code. Use with care.
+// to update frames, first call this:
+void CSQCModel_InterpolateAnimation_2To4_PreNote(float sf);
+void CSQCModel_InterpolateAnimation_1To2_PreNote(float sf);
+// then update frame, frame1time (and possibly frame2, frame2time, lerpfrac)
+// if set_times is not set, caller is responsible for frame1time, frame2time, csqcmodel_lerpfractime!
+void CSQCModel_InterpolateAnimation_2To4_Note(float sf, float set_times);
+void CSQCModel_InterpolateAnimation_1To2_Note(float sf, float set_times);
+// to retrieve animation state, call this
+void CSQCModel_InterpolateAnimation_2To4_Do();
+void CSQCModel_InterpolateAnimation_1To2_Do();
+// will overwrite lerpfrac, lerpfrac3, lerpfrac4, and possibly clear frame*time if they are undisplayed according to lerpfracs
var float autocvar_cl_movement_errorcompensation = 0;
// engine stuff
-.float pmove_flags;
-float pmove_onground; // weird engine flag we shouldn't really use but have to for now
-#define PMF_JUMP_HELD 1
-#define PMF_DUCKED 4
-#define PMF_ONGROUND 8
#define REFDEFFLAG_TELEPORTED 1
#define REFDEFFLAG_JUMPING 2
+float pmove_onground; // weird engine flag we shouldn't really use but have to for now
vector csqcplayer_origin, csqcplayer_velocity;
float csqcplayer_sequence, player_pmflags;
}
CSQCPlayer_PredictTo(clientcommandframe + 1, TRUE);
+#ifdef CSQCMODEL_SERVERSIDE_CROUCH
+ // get crouch state from the server (LAG)
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
+ self.pmove_flags &~= PMF_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
+ self.pmove_flags |= PMF_DUCKED;
+#endif
+
CSQCPlayer_SetMinsMaxs();
self.angles_y = input_angles_y;
#define CSQCPLAYERSTATUS_FROMSERVER 1
#define CSQCPLAYERSTATUS_PREDICTED 2
+// only ever READ these!
+.float pmove_flags;
+#define PMF_JUMP_HELD 1
+#define PMF_DUCKED 4
+#define PMF_ONGROUND 8
+
void CSQCPlayer_SetCamera();
float CSQCPlayer_PreUpdate();
float CSQCPlayer_PostUpdate();
.float lerpfrac;
#define CSQCMODEL_PROPERTY_FRAME 32768
-#define CSQCMODEL_PROPERTY_FRAME2 16384
-#define CSQCMODEL_PROPERTY_LERPFRAC 8192
-#define CSQCMODEL_PROPERTY_TELEPORTED 4096 // the "teleport bit" cancelling interpolation
-#define CSQCMODEL_PROPERTY_MODELINDEX 2048
-#define CSQCMODEL_PROPERTY_ORIGIN 1024
-#define CSQCMODEL_PROPERTY_YAW 512
-#define CSQCMODEL_PROPERTY_PITCHROLL 256
+#define CSQCMODEL_PROPERTY_TELEPORTED 16384 // the "teleport bit" cancelling interpolation
+#define CSQCMODEL_PROPERTY_MODELINDEX 8192
+#define CSQCMODEL_PROPERTY_ORIGIN 4096
+#define CSQCMODEL_PROPERTY_YAW 2048
+#define CSQCMODEL_PROPERTY_PITCHROLL 1024
+#define CSQCMODEL_PROPERTY_FRAME2 512
+#define CSQCMODEL_PROPERTY_LERPFRAC 256
#define ALLPROPERTIES_COMMON \
CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, float, ReadByte, WriteByte, frame) \
if(self.iorigin2 != self.iorigin1)
self.angles = vectoangles(self.iorigin2 - self.iorigin1);
+ if(self.iflags & IFLAG_AUTOVELOCITY)
+ if(self.itime2 != self.itime1)
+ self.velocity = (self.iorigin2 - self.iorigin1) * (1.0 / (self.itime2 - self.itime1));
+
if(self.iflags & IFLAG_ANGLES)
{
fixedmakevectors(self.angles);
#define IFLAG_VALID 8
#define IFLAG_PREVALID 16
#define IFLAG_TELEPORTED 32
+#define IFLAG_AUTOVELOCITY 64
#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
// call this BEFORE reading an entity update
float autocvar_sv_maxairstrafespeed;
float autocvar_sv_maxspeed;
string autocvar_sv_motd;
-float autocvar_sv_player_jumpanim_minfall;
float autocvar_sv_precacheplayermodels;
float autocvar_sv_precacheweapons;
float autocvar_sv_q3acompat_machineshotgunswap;
self.prevorigin = self.origin;
- if (!self.vehicle)
- if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x && !self.freezetag_frozen) // prevent crouching if using melee attack
+ float do_crouch = self.BUTTON_CROUCH;
+ if(self.hook.state)
+ do_crouch = 0;
+ if(self.health <= g_bloodloss)
+ do_crouch = 1;
+ if(self.vehicle)
+ do_crouch = 0;
+ if(self.freezetag_frozen)
+ do_crouch = 0;
+ if(self.weapon == WEP_SHOTGUN && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+ do_crouch = 0;
+
+ if (do_crouch)
{
if (!self.crouch)
{
self.flags &~= FL_ONGROUND;
self.flags &~= FL_JUMPRELEASED;
- if (self.crouch)
- setanim(self, self.anim_duckjump, FALSE, TRUE, TRUE);
- else if (self.animstate_startframe != self.anim_melee_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // jump animation shouldn't override melee until we have animation blending (or until the anim finished, 21/20 = numframes/fps)
- setanim(self, self.anim_jump, FALSE, TRUE, TRUE);
+ animdecide_setaction(self, ANIMACTION_JUMP, TRUE);
if(g_jump_grunt)
PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
self.effects = oldself.effects;
self.glowmod = oldself.glowmod;
self.event_damage = oldself.event_damage;
- self.animstate_startframe = oldself.animstate_startframe;
- self.animstate_numframes = oldself.animstate_numframes;
- self.animstate_framerate = oldself.animstate_framerate;
- self.animstate_starttime = oldself.animstate_starttime;
- self.animstate_endtime = oldself.animstate_endtime;
- self.animstate_override = oldself.animstate_override;
- self.animstate_looping = oldself.animstate_looping;
+ self.anim_state = oldself.anim_state;
+ self.anim_time = oldself.anim_time;
+ self.anim_lower_action = oldself.anim_lower_action;
+ self.anim_lower_time = oldself.anim_lower_time;
+ self.anim_upper_action = oldself.anim_upper_action;
+ self.anim_upper_time = oldself.anim_upper_time;
+ self.anim_implicit_state = oldself.anim_implicit_state;
+ self.anim_implicit_time = oldself.anim_implicit_time;
+ self.anim_lower_implicit_action = oldself.anim_lower_implicit_action;
+ self.anim_lower_implicit_time = oldself.anim_lower_implicit_time;
+ self.anim_upper_implicit_action = oldself.anim_upper_implicit_action;
+ self.anim_upper_implicit_time = oldself.anim_upper_implicit_time;
self.dphitcontentsmask = oldself.dphitcontentsmask;
self.death_time = oldself.death_time;
- self.frame = oldself.frame;
self.pain_finished = oldself.pain_finished;
self.health = oldself.health;
self.armorvalue = oldself.armorvalue;
self.CopyBody_think = oldself.think;
self.nextthink = time;
self.think = CopyBody_Think;
+ // "bake" the current animation frame for clones (they don't get clientside animation)
+ animdecide_setframes(self, FALSE, frame, frame1time, frame2, frame2time);
self = oldself;
}
void player_setupanimsformodel()
{
- // defaults for legacy .zym models without animinfo files
- self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds
- self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds
- self.anim_draw = animfixfps(self, '2 1 3');
- // self.anim_duck = '3 1 100'; // This anim is broken, use slot 3 as a new free slot in the future ;)
- self.anim_duckwalk = animfixfps(self, '4 1 1');
- self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
- self.anim_duckidle = animfixfps(self, '6 1 1');
- self.anim_idle = animfixfps(self, '7 1 1');
- self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
- self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds
- self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds
- self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate
- self.anim_taunt = animfixfps(self, '12 1 0.33');
- self.anim_run = animfixfps(self, '13 1 1');
- self.anim_runbackwards = animfixfps(self, '14 1 1');
- self.anim_strafeleft = animfixfps(self, '15 1 1');
- self.anim_straferight = animfixfps(self, '16 1 1');
- //self.anim_dead1 = animfixfps(self, '17 1 1');
- //self.anim_dead2 = animfixfps(self, '18 1 1');
- self.anim_forwardright = animfixfps(self, '19 1 1');
- self.anim_forwardleft = animfixfps(self, '20 1 1');
- self.anim_backright = animfixfps(self, '21 1 1');
- self.anim_backleft = animfixfps(self, '22 1 1');
- self.anim_melee = animfixfps(self, '23 1 1');
- self.anim_duckwalkbackwards = animfixfps(self, '24 1 1');
- self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1');
- self.anim_duckwalkstraferight = animfixfps(self, '26 1 1');
- self.anim_duckwalkforwardright = animfixfps(self, '27 1 1');
- self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1');
- self.anim_duckwalkbackright = animfixfps(self, '29 1 1');
- self.anim_duckwalkbackleft = animfixfps(self, '30 1 1');
- // TODO introspect models for finding right "fps" value (1/duration)
- // reset animstate now
- setanim(self, self.anim_idle, TRUE, FALSE, TRUE);
+ // load animation info
+ animdecide_init(self);
+ animdecide_setstate(self, 0, FALSE);
}
void player_anim (void)
{
- updateanim(self);
- if (self.weaponentity)
- updateanim(self.weaponentity);
-
- if (self.deadflag != DEAD_NO)
- return;
-
- if (!self.animstate_override)
- {
- if (self.freezetag_frozen)
- setanim(self, self.anim_idle, TRUE, FALSE, FALSE);
- else if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP)
- {
- if (self.crouch)
- {
- if (self.animstate_startframe != self.anim_duckjump_x) // don't perform another trace if already playing the crouch jump anim
- {
- traceline(self.origin + '0 0 1' * PL_CROUCH_MIN_z, self.origin + '0 0 1' * (PL_CROUCH_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
- if(!trace_startsolid && trace_fraction == 1 || !(self.animstate_startframe == self.anim_duckwalk_x || self.animstate_startframe == self.anim_duckidle_x)) // don't get stuck on non-crouch anims
- {
- setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump);
- self.restart_jump = FALSE;
- }
- }
- }
- else
- {
- if (self.animstate_startframe != self.anim_jump_x) // don't perform another trace if already playing the jump anim
- {
- traceline(self.origin + '0 0 1' * PL_MIN_z, self.origin + '0 0 1' * (PL_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
- if(!trace_startsolid && trace_fraction == 1 || self.animstate_startframe == self.anim_idle_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // don't get stuck on idle animation in midair, nor melee after it finished
- {
- setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump);
- self.restart_jump = FALSE;
- }
- }
- }
- }
- else if (self.crouch)
- {
- if (self.movement_x > 0 && self.movement_y == 0)
- setanim(self, self.anim_duckwalk, TRUE, FALSE, FALSE);
- else if (self.movement_x < 0 && self.movement_y == 0)
- setanim(self, self.anim_duckwalkbackwards, TRUE, FALSE, FALSE);
- else if (self.movement_x == 0 && self.movement_y > 0)
- setanim(self, self.anim_duckwalkstraferight, TRUE, FALSE, FALSE);
- else if (self.movement_x == 0 && self.movement_y < 0)
- setanim(self, self.anim_duckwalkstrafeleft, TRUE, FALSE, FALSE);
- else if (self.movement_x > 0 && self.movement_y > 0)
- setanim(self, self.anim_duckwalkforwardright, TRUE, FALSE, FALSE);
- else if (self.movement_x > 0 && self.movement_y < 0)
- setanim(self, self.anim_duckwalkforwardleft, TRUE, FALSE, FALSE);
- else if (self.movement_x < 0 && self.movement_y > 0)
- setanim(self, self.anim_duckwalkbackright, TRUE, FALSE, FALSE);
- else if (self.movement_x < 0 && self.movement_y < 0)
- setanim(self, self.anim_duckwalkbackleft, TRUE, FALSE, FALSE);
- else
- setanim(self, self.anim_duckidle, TRUE, FALSE, FALSE);
- }
- else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20)
- {
- if (self.movement_x > 0 && self.movement_y == 0)
- setanim(self, self.anim_run, TRUE, FALSE, FALSE);
- else if (self.movement_x < 0 && self.movement_y == 0)
- setanim(self, self.anim_runbackwards, TRUE, FALSE, FALSE);
- else if (self.movement_x == 0 && self.movement_y > 0)
- setanim(self, self.anim_straferight, TRUE, FALSE, FALSE);
- else if (self.movement_x == 0 && self.movement_y < 0)
- setanim(self, self.anim_strafeleft, TRUE, FALSE, FALSE);
- else if (self.movement_x > 0 && self.movement_y > 0)
- setanim(self, self.anim_forwardright, TRUE, FALSE, FALSE);
- else if (self.movement_x > 0 && self.movement_y < 0)
- setanim(self, self.anim_forwardleft, TRUE, FALSE, FALSE);
- else if (self.movement_x < 0 && self.movement_y > 0)
- setanim(self, self.anim_backright, TRUE, FALSE, FALSE);
- else if (self.movement_x < 0 && self.movement_y < 0)
- setanim(self, self.anim_backleft, TRUE, FALSE, FALSE);
- else
- setanim(self, self.anim_run, TRUE, FALSE, FALSE);
- }
+ float deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+ if(self.deadflag && !deadbits)
+ if(random() < 0.5)
+ deadbits = ANIMSTATE_DEAD1;
else
- setanim(self, self.anim_idle, TRUE, FALSE, FALSE);
- }
+ deadbits = ANIMSTATE_DEAD2;
+ float animbits = deadbits;
+ if(self.freezetag_frozen)
+ animbits |= ANIMSTATE_FROZEN;
+ if(self.crouch)
+ animbits |= ANIMSTATE_DUCK;
+ animdecide_setstate(self, animbits, FALSE);
+ animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
+
+#ifndef NO_LEGACY_NETWORKING
+ if(!self.iscsqcmodel)
+ animdecide_setframes(self, FALSE, frame, frame1time, frame2, frame2time);
+#endif
if (self.weaponentity)
- if (!self.weaponentity.animstate_override)
- setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE);
+ {
+ updateanim(self.weaponentity);
+ if (!self.weaponentity.animstate_override)
+ setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE);
+ }
}
void SpawnThrownWeapon (vector org, float w)
if (!self.animstate_override)
{
if (random() > 0.5)
- setanim(self, self.anim_pain1, FALSE, TRUE, TRUE);
+ animdecide_setaction(self, ANIMACTION_PAIN1, TRUE);
else
- setanim(self, self.anim_pain2, FALSE, TRUE, TRUE);
+ animdecide_setaction(self, ANIMACTION_PAIN2, TRUE);
}
}
self.respawn_countdown = -1; // do not count down
self.death_time = time;
if (random() < 0.5)
- setanim(self, self.anim_die1, FALSE, TRUE, TRUE);
+ animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD1, TRUE);
else
- setanim(self, self.anim_die2, FALSE, TRUE, TRUE);
+ animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD2, TRUE);
if (self.maxs_z > 5)
{
self.maxs_z = 5;
case VOICETYPE_TAUNT:
if(self.classname == "player")
if(self.deadflag == DEAD_NO)
- setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
+ animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
if(!sv_taunt)
break;
if(sv_gentle)
case VOICETYPE_TAUNT:
if(self.classname == "player")
if(self.deadflag == DEAD_NO)
- setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
+ animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
if(!sv_taunt)
break;
if(sv_gentle)
setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below
// preset some defaults that work great for renamed zym files (which don't need an animinfo)
- self.anim_fire1 = animfixfps(self, '0 1 0.01');
- self.anim_fire2 = animfixfps(self, '1 1 0.01');
- self.anim_idle = animfixfps(self, '2 1 0.01');
- self.anim_reload = animfixfps(self, '3 1 0.01');
+ self.anim_fire1 = animfixfps(self, '0 1 0.01', '0 0 0');
+ self.anim_fire2 = animfixfps(self, '1 1 0.01', '0 0 0');
+ self.anim_idle = animfixfps(self, '2 1 0.01', '0 0 0');
+ self.anim_reload = animfixfps(self, '3 1 0.01', '0 0 0');
// if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
// if we don't, this is a "real" animated model
self.weapon_think = func;
//dprint("next ", ftos(self.weapon_nextthink), "\n");
- // The shoot animation looks TERRIBLE without animation blending! Yay for moonwalking while shooting!
- //anim = self.anim_shoot;
- if (restartanim)
- if (t)
- if (!self.crouch) // shoot anim stands up, this looks bad
+ if((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
{
- vector anim;
- if(self.weapon == WEP_SHOTGUN && self.BUTTON_ATCK2)
- {
- anim = self.anim_melee;
- anim_z = anim_y / (t + sys_frametime);
- setanim(self, anim, FALSE, TRUE, TRUE);
- }
- else if (self.animstate_startframe == self.anim_idle_x) // only allow shoot anim to override idle animation until we have animation blending
- {
- anim = self.anim_shoot;
- anim_z = anim_y / (t + sys_frametime);
- setanim(self, anim, FALSE, TRUE, TRUE);
- }
+ if(self.weapon == WEP_SHOTGUN && fr == WFRAME_FIRE2)
+ animdecide_setaction(self, ANIMACTION_MELEE, restartanim);
+ else
+ animdecide_setaction(self, ANIMACTION_SHOOT, restartanim);
+ }
+ else
+ {
+ if(self.anim_upper_action == ANIMACTION_SHOOT || self.anim_upper_action == ANIMACTION_MELEE)
+ self.anim_upper_action = 0;
}
}
.float animstate_override;
.float animstate_looping;
-// player animation data for this model
-// each vector is as follows:
-// _x = startframe
-// _y = numframes
-// _z = framerate
-.vector anim_die1; // player dies
-.vector anim_die2; // player dies differently
-.vector anim_draw; // player pulls out a weapon
-// .vector anim_duck; // player crouches (from idle to duckidle)
-.vector anim_duckwalk; // player walking while crouching
-.vector anim_duckjump; // player jumping from a crouch
-.vector anim_duckidle; // player idling while crouching
-.vector anim_idle; // player standing
-.vector anim_jump; // player jump
-.vector anim_pain1; // player flinches from pain
-.vector anim_pain2; // player flinches from pain, differently
-.vector anim_shoot; // player shoots
-.vector anim_taunt; // player taunts others (FIXME: no code references this)
-.vector anim_run; // player running forward
-.vector anim_runbackwards; // player running backward
-.vector anim_strafeleft; // player shuffling left quickly
-.vector anim_straferight; // player shuffling right quickly
-//.vector anim_dead1; // player dead (must be identical to last frame of die1)
-//.vector anim_dead2; // player dead (must be identical to last frame of die2)
-.vector anim_forwardright; // player running forward and right
-.vector anim_forwardleft; // player running forward and left
-.vector anim_backright; // player running backward and right
-.vector anim_backleft; // player running back and left
-.vector anim_melee; // player doing the melee action
-.vector anim_duck; // player doing the melee action
-.vector anim_duckwalkbackwards;
-.vector anim_duckwalkstrafeleft;
-.vector anim_duckwalkstraferight;
-.vector anim_duckwalkforwardright;
-.vector anim_duckwalkforwardleft;
-.vector anim_duckwalkbackright;
-.vector anim_duckwalkbackleft;
-
// weapon animation vectors:
.vector anim_fire1;
.vector anim_fire2;
//print(ftos(time), " -> ", ftos(e.frame), "\n");
}
-vector animfixfps(entity e, vector a)
-{
- // multi-frame anim: keep as-is
- if(a_y == 1)
- {
- float dur;
- dur = frameduration(e.modelindex, a_x);
- if(dur > 0)
- a_z = 1.0 / dur;
- }
- return a;
-}
-
/*
==================
SUB_Remove
if (autocvar_sv_dodging_sound == 1)
PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
- setanim(self, self.anim_jump, TRUE, FALSE, TRUE);
+ animdecide_setaction(self, ANIMACTION_JUMP, TRUE);
self.dodging_single_action = 0;
}
../common/command/generic.qh
../common/command/shared_defs.qh
../common/net_notice.qh
+../common/animdecide.qh
autocvars.qh
constants.qh
../warpzonelib/util_server.qc
../warpzonelib/server.qc
+../common/animdecide.qc
../common/util.qc
../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
else
other.lastteleporttime = time;
- if (!other.animstate_override)
if (other.deadflag == DEAD_NO)
- {
- if (other.crouch)
- setanim(other, other.anim_duckjump, FALSE, TRUE, TRUE);
- else
- setanim(other, other.anim_jump, FALSE, TRUE, TRUE);
- }
+ animdecide_setaction(other, ANIMACTION_JUMP, TRUE);
}
else
other.jumppadcount = TRUE;
{
if(autocvar_g_balance_electro_lightning)
if(self.BUTTON_ATCK_prev)
- {
- // prolong the animtime while the gun is being fired
- if(self.animstate_startframe == self.anim_shoot_x && self.animstate_numframes == self.anim_shoot_y)
- weapon_thinkf(WFRAME_DONTCHANGE, autocvar_g_balance_electro_primary_animtime, w_ready);
- else
- weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
- }
+ weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready);
+
if (weapon_prepareattack(0, (autocvar_g_balance_electro_lightning ? 0 : autocvar_g_balance_electro_primary_refire)))
{
if(autocvar_g_balance_electro_lightning)
}
}
if (self.clip_load >= 0) // we are not currently reloading
- if (!self.crouch) // we are not currently crouching; this fixes an exploit where your melee anim is not visible, and besides wouldn't make much sense
+ if (!self.crouch) // no crouchmelee please
if (self.BUTTON_ATCK2 && autocvar_g_balance_shotgun_secondary)
if (weapon_prepareattack(1, autocvar_g_balance_shotgun_secondary_refire))
{