X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fcl_player.qc;h=630cad61fbc1f0c7bde31a9fc6800f4e3a79ca06;hp=e5e0c1dda5516b22ce098311cdc239db3369899f;hb=3adaa0873ad9eac20f32e6e3fc0455d4f9e044cd;hpb=06ee57203283ee16b27a716619866d0a524b6505 diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index e5e0c1dda5..630cad61fb 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -1,126 +1,3 @@ -.entity accuracy; -.float accuracy_frags[WEP_MAXCOUNT]; - -float weaponstats_buffer; - -void WeaponStats_Init() -{ - if(autocvar_sv_weaponstats_file != "") - weaponstats_buffer = buf_create(); - else - weaponstats_buffer = -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_ready(entity fh, entity pass, float status) -{ - float i, j, n, ibot, jbot, idx; - vector v; - string prefix, s; - switch(status) - { - case URL_READY_CANWRITE: - // we can write - prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t"); - url_fputs(fh, "#begin statsfile\n"); - url_fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n")); -#ifdef WATERMARK - url_fputs(fh, strcat("#version ", WATERMARK, "\n")); -#endif - url_fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_purechanges)), "\n")); - url_fputs(fh, strcat("#cvar_purechanges ", ftos(cvar_purechanges_count), "\n")); - n = tokenizebyseparator(cvar_purechanges, "\n"); - for(i = 0; i < n; ++i) - url_fputs(fh, strcat("#cvar_purechange ", argv(i), "\n")); - 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, ibot, j, jbot); - v = stov(bufstr_get(weaponstats_buffer, idx)); - if(v != '0 0 0') - { - //vector is: kills hits damage - url_fputs(fh, sprintf("%s%d %d\t%d %d\t", prefix, i, ibot, j, jbot)); - url_fputs(fh, sprintf("%d %d %g\n", v_x, v_y, v_z)); - } - } - url_fputs(fh, "#end\n\n"); - url_fclose(fh); - break; - case URL_READY_CANREAD: - // url_fclose is processing, we got a response for writing the data - // this must come from HTTP - print("Got response from weapon stats server:\n"); - while((s = url_fgets(fh))) - print(" ", s, "\n"); - print("End of response.\n"); - url_fclose(fh); - break; - case URL_READY_CLOSED: - // url_fclose has finished - print("Weapon stats written\n"); - buf_del(weaponstats_buffer); - weaponstats_buffer = -1; - break; - case URL_READY_ERROR: - default: - print("Weapon stats writing failed: ", ftos(status), "\n"); - buf_del(weaponstats_buffer); - weaponstats_buffer = -1; - break; - } -} - -void WeaponStats_Shutdown() -{ - if(weaponstats_buffer < 0) - return; - if(autocvar_sv_weaponstats_file != "") - { - url_multi_fopen(autocvar_sv_weaponstats_file, FILE_APPEND, WeaponStats_ready, world); - } - else - { - buf_del(weaponstats_buffer); - weaponstats_buffer = -1; - } -} - -void WeaponStats_LogItem(float awep, float abot, float vwep, float vbot, vector item) -{ - float idx; - if(weaponstats_buffer < 0) - return; - if(awep < WEP_FIRST || vwep < WEP_FIRST) - return; - if(awep > WEP_LAST || vwep > WEP_LAST) - return; - 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 abot, float vwep, float vbot, float damage) -{ - if(damage < 0) - error("negative damage?"); - WeaponStats_LogItem(awep, abot, vwep, vbot, '0 0 1' * damage + '0 1 0'); -} -void WeaponStats_LogKill(float awep, float abot, float vwep, float vbot) -{ - WeaponStats_LogItem(awep, abot, vwep, vbot, '1 0 0'); -} - -// changes by LordHavoc on 03/29/04 and 03/30/04 at Vermeulen's request -// merged player_run and player_stand to player_anim -// added death animations to player_anim -// can now spawn thrown weapons from anywhere, not just from players -// thrown weapons now fade out after 20 seconds -// created PlayerGib function -// PlayerDie no longer uses hitloc or damage -// PlayerDie now supports dying animations as well as gibbing -// cleaned up PlayerDie a lot -// added CopyBody - .entity pusher; .float pushltime; .float istypefrag; @@ -155,6 +32,7 @@ void CopyBody(float keepvelocity) self.teleportable = oldself.teleportable; self.damagedbycontents = oldself.damagedbycontents; self.angles = oldself.angles; + self.v_angle = oldself.v_angle; self.avelocity = oldself.avelocity; self.classname = "body"; self.damageforcescale = oldself.damageforcescale; @@ -260,13 +138,6 @@ void player_anim (void) } } -void SpawnThrownWeapon (vector org, float w) -{ - if(self.weapons & WepSet_FromWeapon(self.weapon)) - 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) { float take, save; @@ -276,7 +147,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, autocvar_g_balance_armor_blockpercent, damage); + v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage); take = v_x; save = v_y; @@ -321,11 +192,107 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float } } +// g__str: +// If 0, default is used. +// If <0, 0 is used. +// Otherwise, g_str (default value) is used. +// For consistency, negative values there are mapped to zero too. +#define GAMETYPE_DEFAULTED_SETTING(str) \ + ((gametype_setting_tmp = cvar(strcat("g_", GetGametype(), "_" #str))), \ + (gametype_setting_tmp < 0) ? 0 : \ + (gametype_setting_tmp == 0) ? max(0, autocvar_g_##str) : \ + gametype_setting_tmp) + + +void calculate_player_respawn_time() +{ + float gametype_setting_tmp; + float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max); + float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small); + float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large); + float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count); + float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count); + float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves); + + float pcount = 1; // Include myself whether or not team is already set right and I'm a "player". + entity pl; + if (teamplay) + { + FOR_EACH_PLAYER(pl) + if (pl != self) + if (pl.team == self.team) + ++pcount; + if (sdelay_small_count == 0) + sdelay_small_count = 1; + if (sdelay_large_count == 0) + sdelay_large_count = 1; + } + else + { + FOR_EACH_PLAYER(pl) + if (pl != self) + ++pcount; + if (sdelay_small_count == 0) + { + if (g_cts) + { + // Players play independently. No point in requiring enemies. + sdelay_small_count = 1; + } + else + { + // Players play AGAINST each other. Enemies required. + sdelay_small_count = 2; + } + } + if (sdelay_large_count == 0) + { + if (g_cts) + { + // Players play independently. No point in requiring enemies. + sdelay_large_count = 1; + } + else + { + // Players play AGAINST each other. Enemies required. + sdelay_large_count = 2; + } + } + } + + float sdelay; + + if (pcount <= sdelay_small_count) + sdelay = sdelay_small; + else if (pcount >= sdelay_large_count) + sdelay = sdelay_large; + else // NOTE: this case implies sdelay_large_count > sdelay_small_count. + sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count); + + if(waves) + self.respawn_time = ceil((time + sdelay) / waves) * waves; + else + self.respawn_time = time + sdelay; + + if(sdelay < sdelay_max) + self.respawn_time_max = time + sdelay_max; + else + self.respawn_time_max = self.respawn_time; + + if((sdelay + waves >= 5.0) && (self.respawn_time - time > 1.75)) + self.respawn_countdown = 10; // first number to count down from is 10 + else + self.respawn_countdown = -1; // do not count down + + if(g_cts || autocvar_g_forced_respawn) + self.respawn_flags = self.respawn_flags | RESPAWN_FORCE; +} + void ClientKill_Now_TeamChange(); void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { - float take, save, waves, sdelay, dh, da, j; + float take, save, dh, da, j; vector v; float valid_damage_for_weaponstats; float excess; @@ -353,7 +320,10 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht ear1 += v_right * -10; ear2 += v_right * +10; d = inflictor.origin - self.origin; - f = (d * v_right) / vlen(d); // this is cos of angle of d and v_right! + if (d) + f = (d * v_right) / vlen(d); // this is cos of angle of d and v_right! + else + f = 0; // Assum ecenter. force = v_right * vlen(force); Violence_GibSplash_At(ear1, force * -1, 2, bound(0, damage, 25) / 2 * (0.5 - 0.5 * f), self, attacker); Violence_GibSplash_At(ear2, force, 2, bound(0, damage, 25) / 2 * (0.5 + 0.5 * f), self, attacker); @@ -372,7 +342,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, damage); + v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage); take = v_x; save = v_y; @@ -454,7 +424,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 * autocvar_g_balance_laser_primary_damage * autocvar_g_balance_selfdamagepercent + 1) + if(!DEATH_ISWEAPON(deathtype, WEP_BLASTER) || attacker != self || self.health < 2 * WEP_CVAR_PRI(blaster, damage) * autocvar_g_balance_selfdamagepercent + 1) // WEAPONTODO: create separate limit for pain notification with laser 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 { @@ -567,21 +537,13 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht frag_deathtype = deathtype; MUTATOR_CALLHOOK(PlayerDies); - weapon_action(self.weapon, WR_PLAYERDEATH); + WEP_ACTION(self.weapon, WR_PLAYERDEATH); RemoveGrapplingHook(self); Portal_ClearAllLater(self); - if(IS_REAL_CLIENT(self)) - { - 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); - } + self.fixangle = TRUE; if(defer_ClientKill_Now_TeamChange) ClientKill_Now_TeamChange(); // can turn player into spectator @@ -617,30 +579,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // dying animation self.deadflag = DEAD_DYING; // when to allow respawn - sdelay = 0; - waves = 0; - sdelay = cvar(strcat("g_", GetGametype(), "_respawn_delay")); - if(!sdelay) - { - 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 = autocvar_g_respawn_waves; - if(waves) - self.respawn_time = ceil((time + sdelay) / waves) * waves; - else - self.respawn_time = time + sdelay; - if((sdelay + waves >= 5.0) && (self.respawn_time - time > 1.75)) - self.respawn_countdown = 10; // first number to count down from is 10 - else - self.respawn_countdown = -1; // do not count down - - if(g_cts || autocvar_g_forced_respawn) - self.respawn_flags = self.respawn_flags | RESPAWN_FORCE; + calculate_player_respawn_time(); self.death_time = time; if (random() < 0.5) @@ -667,7 +606,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // reset fields the weapons may use just in case for (j = WEP_FIRST; j <= WEP_LAST; ++j) { - weapon_action(j, WR_RESETPLAYER); + WEP_ACTION(j, WR_RESETPLAYER); ATTACK_FINISHED_FOR(self, j) = 0; } } @@ -681,7 +620,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f // 0 = reject // -1 = fake accept { - string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr; + string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr, colorprefix; float flood; var .float flood_field; entity head; @@ -694,7 +633,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f msgin = formatmessage(msgin); - if not(IS_PLAYER(source)) + if (!IS_PLAYER(source)) colorstr = "^0"; // black for spectators else if(teamplay) colorstr = Team_ColorCode(source.team); @@ -726,14 +665,19 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f else namestr = source.netname; + if(strdecolorize(namestr) == namestr) + colorprefix = "^3"; + else + colorprefix = "^7"; + if(msgin != "") { if(privatesay) { - msgstr = strcat("\{1}\{13}* ^3", namestr, "^3 tells you: ^7"); + msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7"); privatemsgprefixlen = strlen(msgstr); msgstr = strcat(msgstr, msgin); - cmsgstr = strcat(colorstr, "^3", namestr, "^3 tells you:\n^7", msgin); + cmsgstr = strcat(colorstr, colorprefix, namestr, "^3 tells you:\n^7", msgin); if(autocvar_g_chat_teamcolors) privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay), ": ^7"); else @@ -741,12 +685,12 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f } else if(teamsay) { - msgstr = strcat("\{1}\{13}", colorstr, "(^3", namestr, colorstr, ") ^7", msgin); - cmsgstr = strcat(colorstr, "(^3", namestr, colorstr, ")\n^7", msgin); + msgstr = strcat("\{1}\{13}", colorstr, "(", colorprefix, namestr, colorstr, ") ^7", msgin); + cmsgstr = strcat(colorstr, "(", colorprefix, namestr, colorstr, ")\n^7", msgin); } else { - msgstr = strcat("\{1}", namestr, "^7: ", msgin); + msgstr = strcat("\{1}", colorprefix, namestr, "^7: ", msgin); cmsgstr = ""; } msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint @@ -854,9 +798,9 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f } if(!privatesay) - if not(IS_PLAYER(source)) + if (!IS_PLAYER(source)) { - if not(intermission_running) + if (!intermission_running) if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover))) teamsay = -1; // spectators } @@ -900,7 +844,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f { sprint(source, sourcemsgstr); sprint(privatesay, msgstr); - if not(autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled + if (!autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled if(cmsgstr != "") centerprint(privatesay, cmsgstr); } @@ -922,7 +866,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f { sprint(source, sourcemsgstr); dedicated_print(msgstr); // send to server console too - FOR_EACH_REALCLIENT(head) if not(IS_PLAYER(head)) + FOR_EACH_REALCLIENT(head) if (!IS_PLAYER(head)) if(head != source) sprint(head, msgstr); } @@ -1011,7 +955,7 @@ void PrecachePlayerSounds(string f) } fclose(fh); - if not(allvoicesamples) + if (!allvoicesamples) { #define _VOICEMSG(m) allvoicesamples = strcat(allvoicesamples, " ", #m); ALLVOICEMSGS