X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=qcsrc%2Fserver%2Fcl_player.qc;h=f1d290a9b0ae40bccc3b03730e34820d14327739;hb=3f0620ef10b0c142cfb2f64d87af78c1243766c6;hp=8f5b95e3b8e7e29f4801e29428385194d272ee0d;hpb=69ecc894118221039e2cc377d0bf7c46f2db6dcb;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 8f5b95e3b..f1d290a9b 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -2,69 +2,53 @@ float weaponstats_buffer; void WeaponStats_Init() { - if(cvar_string("sv_weaponstats_killfile") != "" || cvar_string("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(cvar_string("hostname"), "\t", GetGametype(), "_", GetMapname(), "\t"); - if(cvar_string("sv_weaponstats_killfile") != "") + prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t"); + if(autocvar_sv_weaponstats_file != "") { - fh = fopen(cvar_string("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(cvar_string("sv_weaponstats_damagefile") != "") - { - fh = fopen(cvar_string("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 @@ -168,7 +152,7 @@ void CopyBody(float keepvelocity) float player_getspecies() { float s; - get_model_parameters(self.playermodel, self.skinindex); + get_model_parameters(self.model, self.skinindex); s = get_model_parameters_species; get_model_parameters(string_null, 0); if(s < 0) @@ -325,11 +309,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) @@ -341,7 +328,7 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float // damage resistance (ignore most of the damage from a bullet or similar) damage = max(damage - 5, 1); - v = healtharmor_applydamage(self.armorvalue, cvar("g_balance_armor_blockpercent"), damage); + v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, damage); take = v_x; save = v_y; @@ -365,13 +352,13 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float self.armorvalue = self.armorvalue - save; self.health = self.health - take; // pause regeneration for 5 seconds - self.pauseregen_finished = max(self.pauseregen_finished, time + cvar("g_balance_pause_health_regen")); + self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_health_regen); } self.dmg_save = self.dmg_save + save;//max(save - 10, 0); 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 <= -150 && self.modelindex != 0) { // don't use any animations as a gib self.frame = 0; @@ -386,12 +373,17 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float } void ClientKill_Now_TeamChange(); +void freezetag_CheckWinner(); void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { 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); @@ -434,12 +426,9 @@ 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, cvar("g_balance_armor_blockpercent"), damage); + v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, damage); take = v_x; save = v_y; } @@ -455,9 +444,10 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht damage_take = take; damage_save = save; damage_force = force; - MUTATOR_CALLHOOK(PlayerDamage); + 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)) { @@ -481,7 +471,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht self.armorvalue = self.armorvalue - save; self.health = self.health - take; // pause regeneration for 5 seconds - self.pauseregen_finished = max(self.pauseregen_finished, time + cvar("g_balance_pause_health_regen")); + self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_health_regen); if (time > self.pain_finished) //Don't switch pain sequences like crazy { @@ -497,7 +487,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht } if(sound_allowed(MSG_BROADCAST, attacker)) - if(!DEATH_ISWEAPON(deathtype, WEP_LASER) || attacker != self || self.health < 2 * cvar("g_balance_laser_primary_damage") * cvar("g_balance_selfdamagepercent") + 1) + if(!DEATH_ISWEAPON(deathtype, WEP_LASER) || attacker != self || self.health < 2 * autocvar_g_balance_laser_primary_damage * autocvar_g_balance_selfdamagepercent + 1) if(self.health > 1) // exclude pain sounds for laserjumps as long as you aren't REALLY low on health and would die of the next two { @@ -537,7 +527,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht else if(attacker.classname == "player" || attacker.classname == "gib") { self.pusher = attacker; - self.pushltime = time + cvar("g_maxpushtime"); + self.pushltime = time + autocvar_g_maxpushtime; } else if(time < self.pushltime) { @@ -547,19 +537,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) @@ -567,8 +566,14 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht float defer_ClientKill_Now_TeamChange; defer_ClientKill_Now_TeamChange = FALSE; + if(self.alivetime) + { + PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime); + self.alivetime = 0; + } + 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)) @@ -595,17 +600,29 @@ 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); + if(!g_freezetag) + { + // 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); + } + // print an obituary message Obituary (attacker, inflictor, self, deathtype); race_PreDie(); DropAllRunes(self); + if(deathtype == DEATH_HURTTRIGGER && g_freezetag) + { + PutClientInServer(); + count_alive_players(); // re-count players + freezetag_CheckWinner(); + return; + } + frag_attacker = attacker; frag_inflictor = inflictor; frag_target = self; @@ -623,8 +640,31 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht if(self.ballcarried && g_nexball) DropBall(self.ballcarried, self.origin, self.velocity); Portal_ClearAllLater(self); - // clear waypoints + + if(clienttype(self) == CLIENTTYPE_REAL) + { + stuffcmd(self, "-zoom\n"); + self.fixangle = TRUE; + //msg_entity = self; + //WriteByte (MSG_ONE, SVC_SETANGLE); + //WriteAngle (MSG_ONE, self.v_angle_x); + //WriteAngle (MSG_ONE, self.v_angle_y); + //WriteAngle (MSG_ONE, 80); + } + + if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag? + ClientKill_Now_TeamChange(); + + if(g_arena) + Spawnqueue_Unmark(self); + + if(g_freezetag) + return; + + // when we get here, player actually dies + // clear waypoints (do this AFTER FreezeTag) WaypointSprite_PlayerDead(); + // make the corpse upright (not tilted) self.angles_x = 0; self.angles_z = 0; @@ -636,7 +676,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht self.movetype = MOVETYPE_TOSS; // shootable corpse self.solid = SOLID_CORPSE; - self.ballistics_density = cvar("g_ballistics_density_corpse"); + self.ballistics_density = autocvar_g_ballistics_density_corpse; // don't stick to the floor self.flags &~= FL_ONGROUND; // dying animation @@ -646,10 +686,15 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht waves = 0; sdelay = cvar(strcat("g_", GetGametype(), "_respawn_delay")); if(!sdelay) - sdelay = cvar("g_respawn_delay"); + { + if(g_cts) + sdelay = 0; // no respawn delay in CTS + else + sdelay = autocvar_g_respawn_delay; + } waves = cvar(strcat("g_", GetGametype(), "_respawn_waves")); if(!waves) - waves = cvar("g_respawn_waves"); + waves = autocvar_g_respawn_waves; if(waves) self.death_time = ceil((time + sdelay) / waves) * waves; else @@ -671,35 +716,19 @@ 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(clienttype(self) == CLIENTTYPE_REAL) - { - self.fixangle = TRUE; - //msg_entity = self; - //WriteByte (MSG_ONE, SVC_SETANGLE); - //WriteAngle (MSG_ONE, self.v_angle_x); - //WriteAngle (MSG_ONE, self.v_angle_y); - //WriteAngle (MSG_ONE, 80); - } - - if(g_arena) - Spawnqueue_Unmark(self); - - if(defer_ClientKill_Now_TeamChange) - ClientKill_Now_TeamChange(); - - if(sv_gentle > 0 || cvar("ekg")) { + if(sv_gentle > 0 || autocvar_ekg) { // remove corpse PlayerCorpseDamage (inflictor, attacker, 100.0, deathtype, hitloc, force); } // reset fields the weapons may use just in case - for (j = WEP_FIRST; j <= WEP_LAST; ++j) + for (j = WEP_FIRST; j <= WEP_LAST; ++j) { - weapon_action(j, WR_RESETPLAYER); + weapon_action(j, WR_RESETPLAYER); ATTACK_FINISHED_FOR(self, j) = 0; } } @@ -764,7 +793,7 @@ void UpdateSelectedPlayer() selected = world; selected_score = 0.95; // 18 degrees - if(!cvar("sv_allow_shownames")) + if(!autocvar_sv_allow_shownames) return; if(clienttype(self) != CLIENTTYPE_REAL) @@ -900,7 +929,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f } */ - if(cvar("g_chat_teamcolors")) + if(autocvar_g_chat_teamcolors) namestr = playername(source); else namestr = source.netname; @@ -913,7 +942,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f privatemsgprefixlen = strlen(msgstr); msgstr = strcat(msgstr, msgin); cmsgstr = strcat(colorstr, "^3", namestr, "^3 tells you:\n^7", msgin); - if(cvar("g_chat_teamcolors")) + if(autocvar_g_chat_teamcolors) privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay), ": ^7"); else privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", privatesay.netname, ": ^7"); @@ -948,23 +977,23 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f float lines; if(privatesay) { - flood_spl = cvar("g_chat_flood_spl_tell"); - flood_burst = cvar("g_chat_flood_burst_tell"); - flood_lmax = cvar("g_chat_flood_lmax_tell"); + flood_spl = autocvar_g_chat_flood_spl_tell; + flood_burst = autocvar_g_chat_flood_burst_tell; + flood_lmax = autocvar_g_chat_flood_lmax_tell; flood_field = floodcontrol_chattell; } else if(teamsay) { - flood_spl = cvar("g_chat_flood_spl_team"); - flood_burst = cvar("g_chat_flood_burst_team"); - flood_lmax = cvar("g_chat_flood_lmax_team"); + flood_spl = autocvar_g_chat_flood_spl_team; + flood_burst = autocvar_g_chat_flood_burst_team; + flood_lmax = autocvar_g_chat_flood_lmax_team; flood_field = floodcontrol_chatteam; } else { - flood_spl = cvar("g_chat_flood_spl"); - flood_burst = cvar("g_chat_flood_burst"); - flood_lmax = cvar("g_chat_flood_lmax"); + flood_spl = autocvar_g_chat_flood_spl; + flood_burst = autocvar_g_chat_flood_burst; + flood_lmax = autocvar_g_chat_flood_lmax; flood_field = floodcontrol_chat; } flood_burst = max(0, flood_burst - 1); @@ -1013,7 +1042,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f if(flood == 2) // cannot happen for empty msgstr { - if(cvar("g_chat_flood_notify_flooder")) + if(autocvar_g_chat_flood_notify_flooder) { sourcemsgstr = strcat(msgstr, "\n^3FLOOD CONTROL: ^7message too long, trimmed\n"); sourcecmsgstr = ""; @@ -1034,7 +1063,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f if(!privatesay) if(source.classname != "player") { - if(teamsay || (cvar("g_chat_nospectators") == 1) || (cvar("g_chat_nospectators") == 2 && !inWarmupStage)) + if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !inWarmupStage)) teamsay = -1; // spectators } @@ -1052,7 +1081,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f } else if(flood == 1) { - if(cvar("g_chat_flood_notify_flooder")) + if(autocvar_g_chat_flood_notify_flooder) { sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.flood_field - time), "^3 seconds\n")); ret = 0; @@ -1124,12 +1153,9 @@ float GetVoiceMessageVoiceType(string type) } string allvoicesamples; -float GetPlayerSoundSampleField_notFound; -float GetPlayerSoundSampleField_fixed; .string GetVoiceMessageSampleField(string type) { GetPlayerSoundSampleField_notFound = 0; - GetPlayerSoundSampleField_fixed = 0; switch(type) { #define _VOICEMSG(m) case #m: return playersound_##m; @@ -1143,7 +1169,6 @@ float GetPlayerSoundSampleField_fixed; .string GetPlayerSoundSampleField(string type) { GetPlayerSoundSampleField_notFound = 0; - GetPlayerSoundSampleField_fixed = 0; switch(type) { #define _VOICEMSG(m) case #m: return playersound_##m; @@ -1205,7 +1230,7 @@ void ClearPlayerSounds() #undef _VOICEMSG } -void LoadPlayerSounds(string f, float first) +float LoadPlayerSounds(string f, float first) { float fh; string s; @@ -1214,7 +1239,7 @@ void LoadPlayerSounds(string f, float first) if(fh < 0) { dprint("Player sound file not found: ", f, "\n"); - return; + return 0; } while((s = fgets(fh))) { @@ -1225,14 +1250,12 @@ void LoadPlayerSounds(string f, float first) field = GetVoiceMessageSampleField(argv(0)); if(GetPlayerSoundSampleField_notFound) continue; - if(GetPlayerSoundSampleField_fixed) - if not(first) - continue; if(self.field) strunzone(self.field); self.field = strzone(strcat(argv(1), " ", argv(2))); } fclose(fh); + return 1; } .float modelindex_for_playersound; @@ -1246,7 +1269,8 @@ void UpdatePlayerSounds() self.skinindex_for_playersound = self.skinindex; ClearPlayerSounds(); LoadPlayerSounds("sound/player/default.sounds", 1); - LoadPlayerSounds(get_model_datafilename(self.playermodel, self.skinindex, "sounds"), 0); + if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skinindex, "sounds"), 0)) + LoadPlayerSounds(get_model_datafilename(self.model, 0, "sounds"), 0); } void FakeGlobalSound(string sample, float chan, float voicetype)