X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=qcsrc%2Fserver%2Fcl_player.qc;h=3e507f4ab644b2bb25f1d2eced3a7a3363e4b178;hb=032028bc6b28d76c43210256a5dadd0d3f71b4a1;hp=bac718356b2ad1b580db3de71bc772ebbdc58067;hpb=04f7d85114bae0e592f9b0ef38d97902ed39f560;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index bac718356..3e507f4ab 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -2,69 +2,53 @@ float weaponstats_buffer; void WeaponStats_Init() { - if(autocvar_sv_weaponstats_killfile != "" || autocvar_sv_weaponstats_damagefile != "") + if(autocvar_sv_weaponstats_file != "") weaponstats_buffer = buf_create(); else weaponstats_buffer = -1; } -#define WEAPONSTATS_GETINDEX(awep,vwep) ((vwep) + (awep) * (WEP_LAST - WEP_FIRST + 1) - (WEP_FIRST + WEP_FIRST * (WEP_LAST - WEP_FIRST + 1))) +#define WEAPONSTATS_GETINDEX(awep,abot,vwep,vbot) (((vwep) + (awep) * (WEP_LAST - WEP_FIRST + 1) - (WEP_FIRST + WEP_FIRST * (WEP_LAST - WEP_FIRST + 1))) * 4 + (abot) * 2 + (vbot)) void WeaponStats_Shutdown() { - float i, j, idx, f; + float i, j, ibot, jbot, idx; float fh; + vector v; string prefix; if(weaponstats_buffer < 0) return; prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t"); - if(autocvar_sv_weaponstats_killfile != "") + if(autocvar_sv_weaponstats_file != "") { - fh = fopen(autocvar_sv_weaponstats_killfile, FILE_APPEND); + fh = fopen(autocvar_sv_weaponstats_file, FILE_APPEND); if(fh >= 0) { - fputs(fh, "#begin killfile\n"); + fputs(fh, "#begin statsfile\n"); fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n")); fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_changes)), "\n")); - for(i = WEP_FIRST; i <= WEP_LAST; ++i) - for(j = WEP_FIRST; j <= WEP_LAST; ++j) + for(i = WEP_FIRST; i <= WEP_LAST; ++i) for(ibot = 0; ibot <= 1; ++ibot) + for(j = WEP_FIRST; j <= WEP_LAST; ++j) for(jbot = 0; jbot <= 1; ++jbot) { - idx = WEAPONSTATS_GETINDEX(i, j); - f = stov(bufstr_get(weaponstats_buffer, idx)) * '0 1 0'; - if(f != 0) - fputs(fh, strcat(prefix, ftos(i), "\t", ftos(j), "\t", ftos(f), "\n")); - } - fputs(fh, "#end\n\n"); - fclose(fh); - print("Weapon kill stats written\n"); - } - } - if(autocvar_sv_weaponstats_damagefile != "") - { - fh = fopen(autocvar_sv_weaponstats_damagefile, FILE_APPEND); - if(fh >= 0) - { - fputs(fh, "#begin damagefile\n"); - fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n")); - fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_changes)), "\n")); - for(i = WEP_FIRST; i <= WEP_LAST; ++i) - for(j = WEP_FIRST; j <= WEP_LAST; ++j) - { - idx = WEAPONSTATS_GETINDEX(i, j); - f = stov(bufstr_get(weaponstats_buffer, idx)) * '1 0 0'; - if(f != 0) - fputs(fh, strcat(prefix, ftos(i), "\t", ftos(j), "\t", ftos(f), "\n")); + idx = WEAPONSTATS_GETINDEX(i, ibot, j, jbot); + v = stov(bufstr_get(weaponstats_buffer, idx)); + if(v != '0 0 0') + { + //vector is: kills hits damage + fputs(fh, sprintf("%s%d %d\t%d %d\t", prefix, i, ibot, j, jbot)); + fputs(fh, sprintf("%d %d %g\n", v_x, v_y, v_z)); + } } fputs(fh, "#end\n\n"); fclose(fh); - print("Weapon damage stats written\n"); + print("Weapon stats written\n"); } } buf_del(weaponstats_buffer); weaponstats_buffer = -1; } -void WeaponStats_LogItem(float awep, float vwep, vector item) +void WeaponStats_LogItem(float awep, float abot, float vwep, float vbot, vector item) { float idx; if(weaponstats_buffer < 0) @@ -73,18 +57,18 @@ void WeaponStats_LogItem(float awep, float vwep, vector item) return; if(awep > WEP_LAST || vwep > WEP_LAST) return; - idx = WEAPONSTATS_GETINDEX(awep,vwep); + idx = WEAPONSTATS_GETINDEX(awep,abot,vwep,vbot); bufstr_set(weaponstats_buffer, idx, vtos(stov(bufstr_get(weaponstats_buffer, idx)) + item)); } -void WeaponStats_LogDamage(float awep, float vwep, float damage) +void WeaponStats_LogDamage(float awep, float abot, float vwep, float vbot, float damage) { if(damage < 0) error("negative damage?"); - WeaponStats_LogItem(awep, vwep, '1 0 0' * damage); + WeaponStats_LogItem(awep, abot, vwep, vbot, '0 0 1' * damage + '0 1 0'); } -void WeaponStats_LogKill(float awep, float vwep) +void WeaponStats_LogKill(float awep, float abot, float vwep, float vbot) { - WeaponStats_LogItem(awep, vwep, '0 1 0'); + WeaponStats_LogItem(awep, abot, vwep, vbot, '1 0 0'); } // changes by LordHavoc on 03/29/04 and 03/30/04 at Vermeulen's request @@ -204,6 +188,7 @@ void player_setupanimsformodel() self.anim_forwardleft = '20 1 1'; self.anim_backright = '21 1 1'; self.anim_backleft = '22 1 1'; + self.anim_melee = '23 1 1'; animparseerror = FALSE; animfilename = strcat(self.model, ".animinfo"); animfile = fopen(animfilename, FILE_READ); @@ -230,6 +215,7 @@ void player_setupanimsformodel() self.anim_forwardleft = animparseline(animfile); self.anim_backright = animparseline(animfile); self.anim_backleft = animparseline(animfile); + self.anim_melee = animparseline(animfile); fclose(animfile); // derived anims @@ -325,11 +311,14 @@ void SpawnThrownWeapon (vector org, float w) { if(self.weapons & W_WeaponBit(j)) if(W_IsWeaponThrowable(j)) - W_ThrowNewWeapon(self, j, FALSE, self.origin, randomvec() * 175 + '0 0 325'); + W_ThrowNewWeapon(self, j, FALSE, org, randomvec() * 175 + '0 0 325'); } } else - W_ThrowWeapon(randomvec() * 125 + '0 0 200', org - self.origin, FALSE); + { + if(W_IsWeaponThrowable(self.weapon)) + W_ThrowNewWeapon(self, self.weapon, FALSE, org, randomvec() * 125 + '0 0 200'); + } } void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) @@ -371,7 +360,7 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float self.dmg_take = self.dmg_take + take;//max(take - 10, 0); self.dmg_inflictor = inflictor; - if (self.health <= -100 && self.modelindex != 0) + if (self.health <= -autocvar_sv_gibhealth && self.modelindex != 0) { // don't use any animations as a gib self.frame = 0; @@ -393,6 +382,10 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht local float take, save, waves, sdelay, dh, da, j; vector v; float valid_damage_for_weaponstats; + float excess; + + if((g_arena && numspawned < 2) || (g_ca && ca_players < required_ca_players) && !inWarmupStage) + return; dh = max(self.health, 0); da = max(self.armorvalue, 0); @@ -435,9 +428,6 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht else Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - if((g_arena && numspawned < 2) || (g_ca && ca_players < required_ca_players) && !inWarmupStage) - return; - if (!g_minstagib) { v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, damage); @@ -459,6 +449,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor); take = bound(0, damage_take, self.health); save = bound(0, damage_save, self.armorvalue); + excess = max(0, damage - take - save); if(sound_allowed(MSG_BROADCAST, attacker)) { @@ -548,19 +539,28 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht else self.pushltime = 0; + float abot, vbot, awep; + abot = (clienttype(attacker) == CLIENTTYPE_BOT); + vbot = (clienttype(self) == CLIENTTYPE_BOT); + valid_damage_for_weaponstats = 0; - if(clienttype(self) == CLIENTTYPE_REAL) - if(clienttype(attacker) == CLIENTTYPE_REAL) - if(self != attacker) - if(!DEATH_ISSPECIAL(deathtype)) + if(vbot || clienttype(self) == CLIENTTYPE_REAL) + if(abot || clienttype(attacker) == CLIENTTYPE_REAL) + if(attacker && self != attacker) if(IsDifferentTeam(self, attacker)) + { + if(DEATH_ISSPECIAL(deathtype)) + awep = attacker.weapon; + else + awep = DEATH_WEAPONOF(deathtype); valid_damage_for_weaponstats = 1; + } if(valid_damage_for_weaponstats) { dh = dh - max(self.health, 0); da = da - max(self.armorvalue, 0); - WeaponStats_LogDamage(DEATH_WEAPONOF(deathtype), self.weapon, dh + da); + WeaponStats_LogDamage(awep, abot, self.weapon, vbot, dh + da); } if (self.health < 1) @@ -575,7 +575,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht } if(valid_damage_for_weaponstats) - WeaponStats_LogKill(DEATH_WEAPONOF(deathtype), self.weapon); + WeaponStats_LogKill(awep, abot, self.weapon, vbot); if(sv_gentle < 1) // TODO make a "gentle" version? if(sound_allowed(MSG_BROADCAST, attacker)) @@ -606,8 +606,6 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht { // become fully visible self.alpha = 1; - // clear selected player display - ClearSelectedPlayer(); // throw a weapon SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon); } @@ -629,6 +627,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht frag_inflictor = inflictor; frag_target = self; MUTATOR_CALLHOOK(PlayerDies); + weapon_action(self.weapon, WR_PLAYERDEATH); if(self.flagcarried) { @@ -718,13 +717,13 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // set damage function to corpse damage self.event_damage = PlayerCorpseDamage; // call the corpse damage function just in case it wants to gib - self.event_damage(inflictor, attacker, 0, deathtype, hitloc, force); + self.event_damage(inflictor, attacker, excess, deathtype, hitloc, force); // set up to fade out later SUB_SetFade (self, time + 6 + random (), 1); if(sv_gentle > 0 || autocvar_ekg) { // remove corpse - PlayerCorpseDamage (inflictor, attacker, 100.0, deathtype, hitloc, force); + PlayerCorpseDamage (inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force); } // reset fields the weapons may use just in case @@ -736,152 +735,70 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht } } -float UpdateSelectedPlayer_countvalue(float v) +// sendflags use: 1 = origin, 2 = health (0 or 1 for dead/alive on enemies), 4 = armor, 0x80 = same team (includes health) +float SendEntity_ShowNames(entity to, float sendflags) { - return max(0, (v - 1.0) / 0.5); + float the_health; + the_health = self.health; + + WriteByte(MSG_ENTITY, ENT_CLIENT_SHOWNAMES); + WriteByte(MSG_ENTITY, num_for_edict(self.owner)); + + sendflags = sendflags & 127; + if(teams_matter && self.owner.team == to.team) + sendflags |= 128; + else if(self.owner.health >= 1) + the_health = 1; + + WriteByte(MSG_ENTITY, sendflags); + if(sendflags & 1) + { + WriteShort(MSG_ENTITY, rint(self.origin_x)); + WriteShort(MSG_ENTITY, rint(self.origin_y)); + WriteShort(MSG_ENTITY, rint(self.origin_z)); + } + if(sendflags & 2) + { + WriteByte(MSG_ENTITY, the_health); + } + if(sendflags & 4) + { + WriteByte(MSG_ENTITY, self.armorvalue); + } + return TRUE; } -// returns: -2 if no hit, otherwise cos of the angle -// uses the global v_angle -float UpdateSelectedPlayer_canSee(entity p, float mincosangle, float maxdist) +const vector SHOWNAMES_ORIGIN_OFFSET = '0 0 48'; +void shownames_think() { - vector so, d; - float c; - - if(p == self) - return -2; - - if(p.deadflag) - return -2; - - so = self.origin + self.view_ofs; - d = p.origin - so; - - // misaimed? - if(dist_point_line(d, '0 0 0', v_forward) > maxdist) - return -2; - - // now find the cos of the angle... - c = normalize(d) * v_forward; - - if(c <= mincosangle) - return -2; - - // not visible in any way? forget it - if(!checkpvs(so, p)) - return -2; - - traceline(so, p.origin, MOVE_NOMONSTERS, self); - if(trace_fraction < 1) - return -2; - - return c; -} - -void ClearSelectedPlayer() -{ - if(self.selected_player) - { - centerprint_expire(self, CENTERPRIO_POINT); - self.selected_player = world; - self.selected_player_display_needs_update = FALSE; - } + if(self.origin - SHOWNAMES_ORIGIN_OFFSET != self.owner.origin) + { + setorigin(self, self.owner.origin + SHOWNAMES_ORIGIN_OFFSET); + self.SendFlags |= 1; + } + if(self.health != max(0, floor(self.owner.health)) || self.armorvalue != max(0, floor(self.owner.armorvalue))) + { + self.health = max(0, floor(self.owner.health)); + self.armorvalue = max(0, floor(self.owner.armorvalue)); + self.SendFlags |= 2; + } + if(self.armorvalue != max(0, floor(self.owner.armorvalue))) + { + self.armorvalue = max(0, floor(self.owner.armorvalue)); + self.SendFlags |= 4; + } + self.nextthink = time; } -void UpdateSelectedPlayer() +float shownames_customize() { - entity selected; - float selected_score; - selected = world; - selected_score = 0.95; // 18 degrees - - if(!autocvar_sv_allow_shownames) - return; - - if(clienttype(self) != CLIENTTYPE_REAL) - return; - - if(self.cvar_cl_shownames == 0) - return; - - if(self.cvar_cl_shownames == 1 && !teams_matter) - return; - - makevectors(self.v_angle); // sets v_forward - - // 1. cursor trace is always right - WarpZone_crosshair_trace(self); - if(trace_ent && trace_ent.classname == "player" && !trace_ent.deadflag) - { - selected = trace_ent; - } - else - { - // 2. if we don't have a cursor trace, find the player which is least - // mis-aimed at - entity p; - FOR_EACH_PLAYER(p) - { - float c; - c = UpdateSelectedPlayer_canSee(p, selected_score, 100); // 100 = 2.5 meters - if(c >= -1) - { - selected = p; - selected_score = c; - } - } - } - - if(selected) - { - self.selected_player_display_timeout = time + self.cvar_scr_centertime; - } - else - { - if(time < self.selected_player_display_timeout) - if(UpdateSelectedPlayer_canSee(self.selected_player, 0.7, 200) >= -1) // 5 meters, 45 degrees - selected = self.selected_player; - } - - if(selected) - { - if(selected == self.selected_player) - { - float save; - save = UpdateSelectedPlayer_countvalue(self.selected_player_count); - self.selected_player_count = self.selected_player_count + frametime; - if(save != UpdateSelectedPlayer_countvalue(self.selected_player_count)) - { - string namestr, healthstr; - namestr = playername(selected); - if(teams_matter) - { - healthstr = ftos(floor(selected.health)); - if(self.team == selected.team) - { - namestr = strcat(namestr, " (", healthstr, "%)"); - self.selected_player_display_needs_update = TRUE; - } - } - centerprint_atprio(self, CENTERPRIO_POINT, namestr); - } - } - else - { - ClearSelectedPlayer(); - self.selected_player = selected; - self.selected_player_time = time; - self.selected_player_count = 0; - self.selected_player_display_needs_update = FALSE; - } - } - else - { - ClearSelectedPlayer(); - } + if(self.owner.classname == "player") // only send players, no spectators! + if(self.owner != other) // no need to spam own coordinates + if(vlen(other.origin - self.origin) < autocvar_sv_shownames_cull_distance) // distance cull + if(self.owner.team == other.team || (self.owner.team != other.team && checkpvs(self.origin, other))) + return TRUE; - if(self.selected_player) - self.last_selected_player = self.selected_player; + return FALSE; } .float muted; // to be used by prvm_edictset server playernumber muted 1