Bug fixes for Killing Floor
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
7.3 KiB

/**
* This feature fixes a bug that can allow players to bypass server's
* friendly fire limitations and teamkill.
* Usual fixes apply friendly fire scale to suspicious damage themselves, which
* also disables some of the environmental damage.
* In order to avoid that, this fix allows server owner to define precisely
* to what damage types to apply the friendly fire scaling.
* It should be all damage types related to projectiles.
* Copyright 2019 - 2021 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class FixFFHack_Feature extends Feature;
/**
* It's possible to bypass friendly fire damage scaling and always deal
* full damage to other players, if one were to either leave the server or
* spectate right after shooting a projectile. We use game rules to catch
* such occurrences and apply friendly fire scaling to weapons,
* specified by server admins.
* To specify required subset of weapons, one must first
* chose a general rule (scale by default / don't scale by default) and then,
* optionally, add exceptions to it.
* Choosing `scaleByDefault == true` as a general rule will make this fix
* behave in the similar way to `KFExplosiveFix` by mutant and will disable
* some environmental sources of damage on some maps. One can then add relevant
* damage classes as exceptions to fix that downside, but making an extensive
* list of such sources might prove problematic.
* On the other hand, setting `scaleByDefault == false` will allow to get
* rid of team-killing exploits by simply adding damage types of all
* projectile weapons, used on a server. This fix comes with such filled-in
* list of all vanilla projectile classes.
*/
// Defines a general rule for choosing whether or not to apply
// friendly fire scaling.
// This can be overwritten by exceptions (`alwaysScale` or `neverScale`).
// Enabling scaling by default without any exceptions in `neverScale` will
// make this fix behave almost identically to Mutant's
// 'Explosives Fix Mutator'.
var private /*config*/ bool scaleByDefault;
// Damage types, for which we should always reapply friendly fire scaling.
var private /*config*/ array< class<DamageType> > alwaysScale;
// Damage types, for which we should never reapply friendly fire scaling.
var private /*config*/ array< class<DamageType> > neverScale;
protected function OnEnabled()
{
_.unreal.gameRules.OnNetDamage(self).connect = NetDamage;
}
protected function OnDisabled()
{
_.unreal.gameRules.OnNetDamage(self).Disconnect();
}
protected function SwapConfig(FeatureConfig config)
{
local FixFFHack newConfig;
newConfig = FixFFHack(config);
if (newConfig == none) {
return;
}
scaleByDefault = newConfig.scaleByDefault;
alwaysScale = newConfig.alwaysScale;
neverScale = newConfig.neverScale;
}
function int NetDamage(
int originalDamage,
int damage,
Pawn injured,
Pawn instigator,
Vector hitLocation,
out Vector momentum,
class<DamageType> damageType)
{
// Something is very wrong and we can just bail on this damage
if (damageType == none) {
return 0;
}
// We only check when suspicious instigators that aren't a world
if (!damageType.default.bCausedByWorld && IsSuspicious(instigator))
{
if (ShouldScaleDamage(damageType))
{
// Remove pushback to avoid environmental kills
momentum = Vect(0.0, 0.0, 0.0);
damage *= _.unreal.GetKFGameType().friendlyFireScale;
}
}
return damage;
}
private function bool IsSuspicious(Pawn instigator)
{
// Instigator vanished
if (instigator == none) return true;
// Instigator already became spectator
if (KFPawn(instigator) != none)
{
if (instigator.playerReplicationInfo != none) {
return instigator.playerReplicationInfo.bOnlySpectator;
}
return true; // Replication info is gone => suspicious
}
return false;
}
// Checks general rule and exception list
public final function bool ShouldScaleDamage(class<DamageType> damageType)
{
local int i;
local array< class<DamageType> > exceptions;
if (damageType == none) return false;
if (scaleByDefault) {
exceptions = neverScale;
}
else {
exceptions = alwaysScale;
}
for (i = 0; i < exceptions.length; i += 1)
{
if (exceptions[i] == damageType) {
return (!scaleByDefault);
}
}
return scaleByDefault;
}
defaultproperties
{
configClass = class'FixFFHack'
scaleByDefault = false
// Vanilla damage types for projectiles
alwaysScale(0) = class'KFMod.DamTypeCrossbuzzsawHeadShot'
alwaysScale(1) = class'KFMod.DamTypeCrossbuzzsaw'
alwaysScale(2) = class'KFMod.DamTypeFrag'
alwaysScale(3) = class'KFMod.DamTypePipeBomb'
alwaysScale(4) = class'KFMod.DamTypeM203Grenade'
alwaysScale(5) = class'KFMod.DamTypeM79Grenade'
alwaysScale(6) = class'KFMod.DamTypeM79GrenadeImpact'
alwaysScale(7) = class'KFMod.DamTypeM32Grenade'
alwaysScale(8) = class'KFMod.DamTypeLAW'
alwaysScale(9) = class'KFMod.DamTypeLawRocketImpact'
alwaysScale(10) = class'KFMod.DamTypeFlameNade'
alwaysScale(11) = class'KFMod.DamTypeFlareRevolver'
alwaysScale(12) = class'KFMod.DamTypeFlareProjectileImpact'
alwaysScale(13) = class'KFMod.DamTypeBurned'
alwaysScale(14) = class'KFMod.DamTypeTrenchgun'
alwaysScale(15) = class'KFMod.DamTypeHuskGun'
alwaysScale(16) = class'KFMod.DamTypeCrossbow'
alwaysScale(17) = class'KFMod.DamTypeCrossbowHeadShot'
alwaysScale(18) = class'KFMod.DamTypeM99SniperRifle'
alwaysScale(19) = class'KFMod.DamTypeM99HeadShot'
alwaysScale(20) = class'KFMod.DamTypeShotgun'
alwaysScale(21) = class'KFMod.DamTypeNailGun'
alwaysScale(22) = class'KFMod.DamTypeDBShotgun'
alwaysScale(23) = class'KFMod.DamTypeKSGShotgun'
alwaysScale(24) = class'KFMod.DamTypeBenelli'
alwaysScale(25) = class'KFMod.DamTypeSPGrenade'
alwaysScale(26) = class'KFMod.DamTypeSPGrenadeImpact'
alwaysScale(27) = class'KFMod.DamTypeSeekerSixRocket'
alwaysScale(28) = class'KFMod.DamTypeSeekerRocketImpact'
alwaysScale(29) = class'KFMod.DamTypeSealSquealExplosion'
alwaysScale(30) = class'KFMod.DamTypeRocketImpact'
alwaysScale(31) = class'KFMod.DamTypeBlowerThrower'
alwaysScale(32) = class'KFMod.DamTypeSPShotgun'
alwaysScale(33) = class'KFMod.DamTypeZEDGun'
alwaysScale(34) = class'KFMod.DamTypeZEDGunMKII'
}