seta scoreboard_offset_right 0.15 "how far (by percent) the scoreboard is offset from the right screen edge"
seta scoreboard_offset_vertical 0.05 "how far (by percent) the scoreboard is offset from the top and bottom of the screen"
seta scoreboard_bg_scale 0.25 "scale for the tiled scoreboard background"
+seta scoreboard_respawntime_decimals 1 "decimal places to show for the respawntime countdown display on the scoreboard"
seta accuracy_color_levels "0 20 100" "accuracy values at which a specified color (accuracy_color<X>) will be used. If your accuracy is between 2 of these values then a mix of the Xth and X+1th colors will be used. You can specify up to 10 values, in increasing order"
seta accuracy_color0 "1 0 0"
float autocvar_scoreboard_offset_left;
float autocvar_scoreboard_offset_right;
float autocvar_scoreboard_offset_vertical;
+float autocvar_scoreboard_respawntime_decimals;
float autocvar_v_flipped;
float autocvar_vid_conheight;
float autocvar_vid_conwidth;
float autocvar_cl_precacheplayermodels;
float autocvar_cl_deathglow;
float autocvar_developer_csqcentities;
+float autocvar__animblend;
else
{
// we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
- float doblend = FALSE;
+ float doblend = autocvar__animblend;
float onground = 0;
if(self == csqcplayer)
{
animdecide_init(self); // FIXME only do this on model change
animdecide_setimplicitstate(self, onground);
animdecide_setframes(self, doblend, anim_frame, anim_frame1time, anim_frame2, anim_frame2time);
+ print(sprintf("frames: %d %d\n", self.anim_frame, self.anim_frame2));
float sf = 0;
if(self.anim_saveframe != self.anim_frame || self.anim_saveframe1time != self.anim_frame1time)
sf |= CSQCMODEL_PROPERTY_FRAME;
CSQCModel_InterpolateAnimation_2To4_Do();
if(doblend)
{
- // build a skeletonobject
+ skeleton_from_frames(self);
}
else
{
- // remove skeletonobject if any
- // all is done
+ free_skeleton_from_frames(self);
+ // just in case, clear these
+ self.lerpfrac3 = 0;
+ self.lerpfrac4 = 0;
}
}
}
--- /dev/null
+.float skeleton_modelindex;
+#define BONETYPE_LOWER 0
+#define BONETYPE_UPPER 1
+#define MAX_BONES 128
+.float skeleton_bonetype[MAX_BONES];
+.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;
+ 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")
+ t = BONETYPE_UPPER;
+ if(nm == "upperarm_R")
+ e.skeleton_aimbone = i;
+ e.(skeleton_bonetype[i-1]) = t;
+ }
+}
+
+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_LOWER && 1)
+ {
+ // only show frames 1+3
+ e.lerpfrac = 0;
+ e.lerpfrac3 = savelerpfrac3 * 2;
+ e.lerpfrac4 = 0;
+ }
+ else
+ {
+ // only show frames 2+4
+ 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 = savelerpfrac;
+ e.lerpfrac4 = savelerpfrac;
+}
--- /dev/null
+void free_skeleton_from_frames(entity e);
+void skeleton_from_frames(entity e);
../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
}
}
-
pos_y += 1.2 * hud_fontsize_y;
drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ // print information about respawn status
+ float respawn_time = getstatf(STAT_RESPAWN_TIME);
+ if(respawn_time)
+ {
+ if(respawn_time < 0)
+ {
+ // a negative number means we are awaiting respawn, time value is still the same
+ respawn_time *= -1; // remove mark now that we checked it
+ if(time >= respawn_time) // don't show a negative value while the server is respawning the player (lag)
+ str = _("^1Respawning...");
+ else
+ str = sprintf(_("^1Respawning in ^3%s^1 seconds..."), ftos_decimals(respawn_time - time, autocvar_scoreboard_respawntime_decimals));
+ }
+ else if(time < respawn_time)
+ str = sprintf(_("You are dead, wait ^3%s^7 seconds before respawning"), ftos_decimals(respawn_time - time, autocvar_scoreboard_respawntime_decimals));
+ else if(time >= respawn_time)
+ str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
+
+ pos_y += 1.2 * hud_fontsize_y;
+ drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ }
+
scoreboard_bottom = pos_y + 2 * hud_fontsize_y;
}
const float STAT_SECRETS_TOTAL = 70;
const float STAT_SECRETS_FOUND = 71;
+const float STAT_RESPAWN_TIME = 72;
+
// mod stats (1xx)
const float STAT_REDALIVE = 100;
const float STAT_BLUEALIVE = 101;
self.dmg_inflictor = spectatee.dmg_inflictor;
self.v_angle = spectatee.v_angle;
self.angles = spectatee.v_angle;
+ self.stat_respawn_time = spectatee.stat_respawn_time;
if(!self.BUTTON_USE)
self.fixangle = TRUE;
setorigin(self, spectatee.origin);
self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
self.stat_leadlimit = autocvar_leadlimit;
+ if(g_arena || (g_ca && !allowed_to_spawn))
+ self.stat_respawn_time = 0;
+ else
+ self.stat_respawn_time = self.respawn_time;
+
if(frametime)
{
// physics frames: update anticheat stuff
}
ShowRespawnCountdown();
}
+
+ // if respawning, invert stat_respawn_time to indicate this, the client translates it
+ if(self.deadflag == DEAD_RESPAWNING && self.stat_respawn_time > 0)
+ self.stat_respawn_time *= -1;
+
return;
}
// FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
take = damage;
}
+ if(attacker == self)
+ {
+ // don't reset pushltime for self damage as it may be an attempt to
+ // escape a lava pit or similar
+ //self.pushltime = 0;
+ self.istypefrag = 0;
+ }
+ else if(attacker.classname == "player")
+ {
+ self.pusher = attacker;
+ self.pushltime = time + autocvar_g_maxpushtime;
+ self.istypefrag = self.BUTTON_CHAT;
+ }
+ else if(time < self.pushltime)
+ {
+ attacker = self.pusher;
+ self.pushltime = max(self.pushltime, time + 0.6);
+ }
+ else
+ {
+ self.pushltime = 0;
+ self.istypefrag = 0;
+ }
+
frag_inflictor = inflictor;
frag_attacker = attacker;
frag_target = self;
self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
self.dmg_inflictor = inflictor;
- if(attacker == self)
- {
- // don't reset pushltime for self damage as it may be an attempt to
- // escape a lava pit or similar
- //self.pushltime = 0;
- self.istypefrag = 0;
- }
- else if(attacker.classname == "player")
- {
- self.pusher = attacker;
- self.pushltime = time + autocvar_g_maxpushtime;
- self.istypefrag = self.BUTTON_CHAT;
- }
- else if(time < self.pushltime)
- {
- attacker = self.pusher;
- self.pushltime = max(self.pushltime, time + 0.6);
- }
- else
- {
- self.pushltime = 0;
- self.istypefrag = 0;
- }
+ if(g_ca && self != attacker && attacker.classname == "player")
+ PlayerScore_Add(attacker, SP_SCORE, (damage - excess) * autocvar_g_ca_damage2score_multiplier);
float abot, vbot, awep;
abot = (clienttype(attacker) == CLIENTTYPE_BOT);
.entity muzzle_flash;
.float misc_bulletcounter; // replaces uzi & hlac bullet counter.
+.float stat_respawn_time; // shows respawn time, and is negative when awaiting respawn
+
void PlayerUseKey();
typedef vector(entity player, entity spot, vector current) spawn_evalfunc_t;
if(deathtype & HITTYPE_HEADSHOT)
headshot = 1;
}
- if(g_ca)
- PlayerScore_Add(attacker, SP_SCORE, damage * autocvar_g_ca_damage2score_multiplier);
}
}
else
// secrets
addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total);
addstat(STAT_SECRETS_FOUND, AS_FLOAT, stat_secrets_found);
+
+ // misc
+ addstat(STAT_RESPAWN_TIME, AS_FLOAT, stat_respawn_time);
next_pingtime = time + 5;
else
{
// otherwise: each hit gets damage back
- frag_attacker.health += damage_take;
+ frag_attacker.health = frag_attacker.health + bound(0, damage_take, self.health);
}
return 0;
}