#include "player.qh"
+#include <common/anim.qh>
+#include <common/animdecide.qh>
+#include <common/csqcmodel_settings.qh>
+#include <common/deathtypes/all.qh>
#include <common/effects/all.qh>
-#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 <common/effects/qc/_mod.qh>
#include <common/gamemodes/_mod.qh>
-
-#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 <common/gamemodes/sv_rules.qh>
+#include <common/mapobjects/_mod.qh>
+#include <common/mapobjects/subs.qh>
+#include <common/mapobjects/teleporters.qh>
+#include <common/minigames/sv_minigames.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
+#include <common/mutators/mutator/waypoints/waypointsprites.qh>
+#include <common/physics/player.qh>
+#include <common/playerstats.qh>
+#include <common/state.qh>
+#include <common/wepent.qh>
+#include <lib/csqcmodel/sv_model.qh>
+#include <server/bot/api.qh>
+#include <server/cheats.qh>
+#include <server/client.qh>
+#include <server/clientkill.qh>
+#include <server/command/common.qh>
+#include <server/command/vote.qh>
+#include <server/damage.qh>
+#include <server/handicap.qh>
+#include <server/hook.qh>
+#include <server/main.qh>
+#include <server/mutators/_mod.qh>
+#include <server/portals.qh>
+#include <server/teamplay.qh>
+#include <server/weapons/accuracy.qh>
+#include <server/weapons/common.qh>
+#include <server/weapons/throwing.qh>
+#include <server/weapons/weaponstats.qh>
+#include <server/weapons/weaponsystem.qh>
+#include <server/world.qh>
void Drop_Special_Items(entity player)
{
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));
}
}
-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)
}
}
- 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
{
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);
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))
{
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
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 (!(round_handler_IsActive() && !round_handler_IsRoundStarted()) && time >= game_starttime)
- {
- 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);
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;
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)
{
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;
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)
GiveResourceWithLimit(targ, RES_HEALTH, amount, limit);
return true;
}
+
+void precache_playermodel(string m)
+{
+ int globhandle, i, n;
+ string f;
+
+ // remove :<skinnumber> 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);
+ }
+}