X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fplayer.qc;h=ad3ba94e4a21d18c9aa7c293a1c68cfa9a04edeb;hb=54c73db251372d28956d780656c4a0a78a2e54ca;hp=9bf3f7c60283db691cbfa8430aeba0ad4a504aec;hpb=c29ff3e1ef498deec2ebd9ad6883e9d2b683f43d;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/player.qc b/qcsrc/server/player.qc index 9bf3f7c60..ad3ba94e4 100644 --- a/qcsrc/server/player.qc +++ b/qcsrc/server/player.qc @@ -1,39 +1,43 @@ #include "player.qh" +#include +#include +#include +#include #include -#include "bot/api.qh" -#include "cheats.qh" -#include "clientkill.qh" -#include "g_damage.qh" -#include "handicap.qh" -#include "miscfunctions.qh" -#include "portals.qh" -#include "teamplay.qh" -#include "weapons/throwing.qh" -#include "command/common.qh" -#include "../common/state.qh" -#include "../common/anim.qh" -#include "../common/animdecide.qh" -#include "../common/csqcmodel_settings.qh" -#include "../common/gamemodes/sv_rules.qh" -#include "../common/deathtypes/all.qh" -#include "../common/mapobjects/subs.qh" -#include "../common/playerstats.qh" -#include "../lib/csqcmodel/sv_model.qh" - -#include "../common/minigames/sv_minigames.qh" - +#include #include - -#include "../common/physics/player.qh" -#include "../common/effects/qc/_mod.qh" -#include "../common/mutators/mutator/waypoints/waypointsprites.qh" -#include "../common/mapobjects/_mod.qh" -#include "../common/wepent.qh" - -#include "weapons/weaponstats.qh" - -#include "../common/animdecide.qh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include void Drop_Special_Items(entity player) { @@ -165,7 +169,7 @@ void player_anim(entity this) animbits |= ANIMSTATE_FROZEN; if(this.move_movetype == MOVETYPE_FOLLOW) animbits |= ANIMSTATE_FOLLOW; - if(this.crouch) + if(IS_DUCKED(this)) animbits |= ANIMSTATE_DUCK; animdecide_setstate(this, animbits, false); animdecide_setimplicitstate(this, IS_ONGROUND(this)); @@ -222,97 +226,11 @@ void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float da } } -void calculate_player_respawn_time(entity this) -{ - if(MUTATOR_CALLHOOK(CalculateRespawnTime, this)) - return; - - 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". - if (teamplay) - { - FOREACH_CLIENT(IS_PLAYER(it) && it != this, { - if(it.team == this.team) - ++pcount; - }); - if (sdelay_small_count == 0) - sdelay_small_count = 1; - if (sdelay_large_count == 0) - sdelay_large_count = 1; - } - else - { - FOREACH_CLIENT(IS_PLAYER(it) && it != this, { - ++pcount; - }); - if (sdelay_small_count == 0) - { - if (IS_INDEPENDENT_PLAYER(this)) - { - // 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 (IS_INDEPENDENT_PLAYER(this)) - { - // 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) - this.respawn_time = ceil((time + sdelay) / waves) * waves; - else - this.respawn_time = time + sdelay; - - if(sdelay < sdelay_max) - this.respawn_time_max = time + sdelay_max; - else - this.respawn_time_max = this.respawn_time; - - if((sdelay + waves >= 5.0) && (this.respawn_time - time > 1.75)) - this.respawn_countdown = 10; // first number to count down from is 10 - else - this.respawn_countdown = -1; // do not count down - - if(autocvar_g_forced_respawn) - this.respawn_flags = this.respawn_flags | RESPAWN_FORCE; -} - void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) { vector v; - float dh = max(GetResource(this, RES_HEALTH), 0); - float da = max(GetResource(this, RES_ARMOR), 0); + float initial_health = max(GetResource(this, RES_HEALTH), 0); + float initial_armor = max(GetResource(this, RES_ARMOR), 0); float take = 0, save = 0; if (damage) @@ -326,8 +244,13 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, } } - if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1) - damage *= 1 - max(0, autocvar_g_spawnshield_blockdamage); + if (STAT(FROZEN, this)) + { + if (!ITEM_DAMAGE_NEEDKILL(deathtype)) + damage = 0; + } + else if (StatusEffects_active(STATUSEFFECT_SpawnShield, this) && autocvar_g_spawnshield_blockdamage < 1) + damage *= 1 - bound(0, autocvar_g_spawnshield_blockdamage, 1); if(deathtype & HITTYPE_SOUND) // sound based attacks cause bleeding from the ears { @@ -398,7 +321,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if(sound_allowed(MSG_BROADCAST, attacker)) { - if (save > 10 && (dh - take) > 0) // don't play armor sound if the attack is fatal + if (save > 10 && (initial_health - take) > 0) // don't play armor sound if the attack is fatal sound (this, CH_SHOTS, SND_ARMORIMPACT, VOL_BASE, ATTEN_NORM); else if (take > 30) sound (this, CH_SHOTS, SND_BODYIMPACT2, VOL_BASE, ATTEN_NORM); @@ -411,7 +334,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if (take > 100) Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker); - if (time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1) + if (!StatusEffects_active(STATUSEFFECT_SpawnShield, this) || autocvar_g_spawnshield_blockdamage < 1) { if (!(this.flags & FL_GODMODE)) { @@ -421,7 +344,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if(take) this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen); - if (time > this.pain_finished) //Don't switch pain sequences like crazy + if (time > this.pain_finished && !STAT(FROZEN, this)) // Don't switch pain sequences like crazy { this.pain_finished = time + 0.5; //Supajoe @@ -465,17 +388,6 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, this.v_angle_y = this.v_angle.y + (random() * 2 - 1) * shake; this.v_angle_x = bound(-90, this.v_angle.x, 90); } - - float realdmg = damage - excess; - if (this != attacker && realdmg) - { - if (IS_PLAYER(attacker) && DIFF_TEAM(attacker, this)) { - GameRules_scoring_add(attacker, DMG, realdmg); - } - if (IS_PLAYER(this)) { - GameRules_scoring_add(this, DMGTAKEN, realdmg); - } - } } else this.max_armorvalue += (save + take); @@ -490,10 +402,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, bool valid_damage_for_weaponstats = false; Weapon awep = WEP_Null; + if (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime) if(vbot || IS_REAL_CLIENT(this)) if(abot || IS_REAL_CLIENT(attacker)) if(attacker && this != attacker) - if(DIFF_TEAM(this, attacker)) + if (DIFF_TEAM(this, attacker) && (!STAT(FROZEN, this) || this.freeze_time > time)) { if(DEATH_ISSPECIAL(deathtype)) awep = attacker.(weaponentity).m_weapon; @@ -502,19 +415,31 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, valid_damage_for_weaponstats = true; } - dh = dh - max(GetResource(this, RES_HEALTH), 0); - da = da - max(GetResource(this, RES_ARMOR), 0); + float dh = initial_health - max(GetResource(this, RES_HEALTH), 0); // health difference + float da = initial_armor - max(GetResource(this, RES_ARMOR), 0); // armor difference if(valid_damage_for_weaponstats) { WeaponStats_LogDamage(awep.m_id, abot, this.(weaponentity).m_weapon.m_id, vbot, dh + da); } - MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype, damage); + bool forbid_logging_damage = MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype, damage); + + if ((dh || da) && !forbid_logging_damage) + { + float realdmg = damage - excess; + if ((this != attacker || deathtype == DEATH_KILL.m_id) && realdmg && !STAT(FROZEN, this) + && (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime)) + { + if (IS_PLAYER(attacker) && DIFF_TEAM(attacker, this) && deathtype != DEATH_KILL.m_id) + GameRules_scoring_add(attacker, DMG, realdmg); + if (IS_PLAYER(this)) + GameRules_scoring_add(this, DMGTAKEN, realdmg); + } + } if (GetResource(this, RES_HEALTH) < 1) { - float defer_ClientKill_Now_TeamChange; - defer_ClientKill_Now_TeamChange = false; + bool defer_ClientKill_Now_TeamChange = false; if(this.alivetime) { @@ -613,8 +538,17 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, this.avelocity = '0 0 0'; // view from the floor this.view_ofs = '0 0 -8'; - // toss the corpse - set_movetype(this, MOVETYPE_TOSS); + if(this.move_movetype == MOVETYPE_NOCLIP) + { + // don't toss the corpse in this case, it can get stuck in solid (causing low fps) + // or fall indefinitely into the void if out of the map + this.velocity = '0 0 0'; + } + else + { + // toss the corpse + set_movetype(this, MOVETYPE_TOSS); + } // shootable corpse this.solid = SOLID_CORPSE; PS(this).ballistics_density = autocvar_g_ballistics_density_corpse; @@ -622,8 +556,10 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, UNSET_ONGROUND(this); // dying animation this.deadflag = DEAD_DYING; + // don't play teleportation sounds + this.teleportable = TELEPORT_SIMPLE; - STAT(MOVEVARS_SPECIALCOMMAND, this) = false; // sweet release + STAT(AIR_FINISHED, this) = 0; this.death_time = time; if (random() < 0.5) @@ -677,3 +613,78 @@ bool PlayerHeal(entity targ, entity inflictor, float amount, float limit) GiveResourceWithLimit(targ, RES_HEALTH, amount, limit); return true; } + +void precache_playermodel(string m) +{ + int globhandle, i, n; + string f; + + // remove : suffix + int j = strstrofs(m, ":", 0); + if(j >= 0) + m = substring(m, 0, j); + + if(substring(m, -9, 5) == "_lod1") + return; + if(substring(m, -9, 5) == "_lod2") + return; + precache_model(m); + f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1)); + if(fexists(f)) + precache_model(f); + f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1)); + if(fexists(f)) + precache_model(f); + + globhandle = search_begin(strcat(m, "_*.sounds"), true, false); + if (globhandle < 0) + return; + n = search_getsize(globhandle); + for (i = 0; i < n; ++i) + { + //print(search_getfilename(globhandle, i), "\n"); + f = search_getfilename(globhandle, i); + PrecachePlayerSounds(f); + } + search_end(globhandle); +} +void precache_all_playermodels(string pattern) +{ + int globhandle = search_begin(pattern, true, false); + if (globhandle < 0) return; + int n = search_getsize(globhandle); + for (int i = 0; i < n; ++i) + { + string s = search_getfilename(globhandle, i); + precache_playermodel(s); + } + search_end(globhandle); +} + +void precache_playermodels(string s) +{ + FOREACH_WORD(s, true, { precache_playermodel(it); }); +} + +PRECACHE(PlayerModels) +{ + // Precache all player models if desired + if (autocvar_sv_precacheplayermodels) + { + PrecachePlayerSounds("sound/player/default.sounds"); + precache_all_playermodels("models/player/*.zym"); + precache_all_playermodels("models/player/*.dpm"); + precache_all_playermodels("models/player/*.md3"); + precache_all_playermodels("models/player/*.psk"); + precache_all_playermodels("models/player/*.iqm"); + } + + if (autocvar_sv_defaultcharacter) + { + precache_playermodels(autocvar_sv_defaultplayermodel_red); + precache_playermodels(autocvar_sv_defaultplayermodel_blue); + precache_playermodels(autocvar_sv_defaultplayermodel_yellow); + precache_playermodels(autocvar_sv_defaultplayermodel_pink); + precache_playermodels(autocvar_sv_defaultplayermodel); + } +}