rott/kf_sources/HideMut/Classes/a_MonsterOptimizer.uc
2026-07-14 20:27:09 +07:00

1389 lines
48 KiB
Ucode

class a_MonsterOptimizer extends a_ActorBase
config(HideMut);
var PlayerController PC;
var float NumSequences;
var int NewTicks, CurrentZone; // for tick comparing
var bool Opt_Launched, // optimizer started
LowGore, // Client Low Gore == KillingFloor.ini, parameter UseLowGore
Cooldown; // Flag for ZoneInfo zed search
var int NumZeds, // Num spawned Zeds
NumberOfZonesChecked; // Number of checked zones
var array<KFMonster> cachedZeds; // cache zeds for culling and other purposes
var array<KFMonster> deadZeds; // cache zeds for ragdoll management
var array<ZoneInfo> ZoneInfos;
var ZoneInfo Zone;
// ========================= Configz
var config array<string> KFMonsterGibClassNames; // Gibs aka severed arms
var config array<string> KFMonsterGibletsClassNames; // giblets - small parts that spawn when arm, leg or etc. has been lost
var config array<string> KFMonsterGibEmitters; // 5000 tons of bloods and particles...
var config array<string> KFMonsterClassNames_Standard, // default monster classes
KFMonsterClassNames_Circus, // Circus
KFMonsterClassNames_Halloween, // Halloween
KFMonsterClassNames_XMas; // Xmas
var config array<string> CustomZeds; // Scrn zeds
var config array<string> NiceZeds; // NiceZeds
var config array<string> LagEmitters; // Firebug shit
var config array<string> TWIGoreBackup, TWIGibEmitters;
// =============================== Structures for optimizer paramas
struct EmitLightControl
{
var bool UseFireTweaks; // Use or not fire tweaks
var float LightRadius; // Light radius for fire emitters
var ELightType LightType; // Light tyoe
var byte LightBrightness;
var byte LightHue; // Color
var byte LightSaturation;
var bool bDynamicLight; // Should be dynamic?
var bool bSpecialLit; // Don't lit dynamic actors
var bool UseAdditionalTweaks; // Use additional tweaks flashlight and etc.
var bool FixDoshLighting; // Attempt to fix dosh mesh lighting
};
// for ambient sounds
struct OptParams
{
var string WholeMapSearchMethod; // Use zoneinfo.zoneactors search or use DynamicActors search
var bool ConsNetSpeed; // Constant net speed
var bool bMonsterSpotted;
var float ZedCullDistance; // Cull distance for zeds
var float Timer;
var int Ticks; // every goddamn tick optimizer will detect decapped zeds
var int nozed_NetSpeed; // NetSpeed without zeds
var int new_NetSpeed; // NetSpeed with zeds
var bool UseUnlit; // if unlit zed will appear in full brightness
var byte AmbientGlow; // if unlit this will regulate zed's brightness
var bool bSeasonedOff; // disable season zeds //replace seasoned(super laggy) zeds with default. Fuk u twi
// for 70 bones skeletons and MSM_Smooth_Only shit. Read dat fucking manual first
var bool bLagOff;
var ESoundOcclusion SoundOcclusion; // Sound occlusion == what will block sounds(bsp, static meshes, none and etc)
var float SoundRadius; // Ambient Sound radius
// ===================== Seasoned zeds shit
var bool bStandard;
var bool bCircus;
var bool bHillBilly;
var bool bXmas;
// ===================== Seasoned zeds shit
// ================================ Gore related tweaks
var string GoreLevel; // my gore level preset for twi classes
// Gibs
var bool bNoRagdolls; // Destroy Ragdolls them
var float RagdollLifeSpan;
var bool bAdvancedGibs;
var bool bUnlitGibs;
var bool bHideGibs;
var float GibsLifespan;
var bool GibUseDeferRendering;
var int GibMaxLights;
var bool GibUseCollisionStaticMesh;
var bool GibAcceptProjectors;
var bool GibStaticLighting;
// Giblets
var bool bAdvancedGiblets;
var bool bUnlitGiblets;
var bool bHideGiblets;
var float GibletsLifespan;
var bool GibletsUseDeferRendering;
var int GibletsMaxLights;
var bool GibletsUseCollisionStaticMesh;
var bool GibletsAcceptProjectors;
var bool GibletsStaticLighting;
// =============================== Gore related tweaks end
var bool UserSettingsToEmitters;
var int ZedSearchRadius;
};
// Emitter backups. Stub. Should rewrite dis
// contains variables from Particle emitter class. Used to backup and edit particle emitter classes
struct EMB
{
var string ClassName; //Particle emitter name
var bool bHidden;
var bool bUnlit;
var bool Disabled; //Disable Emitter
var float InitialParticlesPerSecond; //plz make it 500000000000000000000
var bool UseCollision; //Use collision for emitter particles
var bool AcceptsProjectors; //Accept projectors or don't
var float LifeSpan;
};
struct EMP_backups
{
var string ClassName;
var bool bHidden;
var bool bUnlit;
var float LifeSpan; //lifespan applies to emitter class
var array<EMB> CEMP; //particle emitters array
};
struct GorePresets //Gore presets for my emitters
{
var string PresetName;
var string PresetDescription;
var array<EMP_backups> EmittersToLoad;
};
//===============================Structures for optimizer paramas
var OptParams CurrentOptParams; //Current optimizer parameters
var EmitLightControl LC; //Firebug and lighting shit also dosh meshlighting fix
var EMP_backups EMP_backSingle; //for backuping emitters properties, single emitter
var array<EMP_backups> EMP_back; //for backuping emitters properties, emitters array
var EMB User_EMPS; //User settings for all emitters
var array<GorePresets> Gore_Presets; //Gore_Presets. mb should add custom?
var GorePresets Gore_Preset; //Single Gore Preset for using in structure arrays
var array<class <Emitter> > BackupGore, LowGoreE, OptGore, NoGore;
function startOptimize()
{
local int i;
PC = Level.GetLocalPlayerController();
// Zone infos stuff only dependent to ZoneActors search method
if (CurrentOptParams.WholeMapSearchMethod ~= "ZoneActors")
{
CurrentZone = 0;
ForEach AllActors(class'ZoneInfo', Zone)
{
//PC.ClientMessage(PC.GameReplicationInfo.PRIArray.length);
ZoneInfos[i] = Zone;
i++;
}
for(i=0;i<ZoneInfos.length;i++)
{
if (ZoneInfos[i] == none
|| Instr(CAPS(string(ZoneInfos[i])), "SKY") != -1
|| Instr(CAPS(string(ZoneInfos[i])), "ROCKING") != -1
|| Instr(CAPS(string(ZoneInfos[i])), "WARP") != -1
|| Instr(CAPS(string(ZoneInfos[i])), "LEVEL") != -1)
ZoneInfos.Remove(i,1);
//PC.ClientMessage(ZoneInfos[i]);
}
if (ZoneInfos.length == 0)
{
CurrentOptParams.WholeMapSearchMethod = "AllActors";
PC.ClientMEssage("No zones. Using All actors method");
}
}
if (CurrentOptParams.bSeasonedOff)
RemoveSeasonedZeds();
else
RestoreSeasonedZeds();
LowGore = class'GameInfo'.static.UseLowGore(); //Client Low Gore == KillingFloor.ini, parameter UseLowGore
OptimizeGore(); //Optimize gibs and gilets
if (LC.UseFireTweaks)
FirebugDisabler(); //Disable firebug shit
// Additional tweaks
if (LC.UseAdditionalTweaks)
{
class'SingleAttachment'.default.LightType = LT_Steady; //Why dafuq you put LT_Pulse on flashlight.
class'ZEDMKIIPrimaryProjectileImpact'.default.LightType = LT_Steady;
class'ZEDMKIISecondaryProjectileExplosion'.default.LightType = LT_Steady;
class'ZEDProjectileImpact'.default.LightType = LT_Steady;
}
// Dosh tweak, Remove crazy mesh lighting dosh shit
if (LC.FixDoshLighting)
class'KFMod.CashPickup'.default.bUnlit = true;
if (!Opt_Launched)
{
// Don't start timer if using default class pollution
if (CurrentOptParams.bLagOff)
PolluteDefaults(false);
else
{
SetTimer(CurrentOptParams.Timer, true);
Opt_Launched = true;
if (!LowGore)
Disable('Tick');
else
Enable('Tick');
}
return;
}
else
{
stopOptimize();
Opt_Launched = true;
// Don't start timer if using non-laggy optimization
if (!CurrentOptParams.bLagOff)
SetTimer(CurrentOptParams.Timer, true);
if (!LowGore)
Disable('Tick');
else
Enable('Tick');
}
}
function stopOptimize()
{
local int i;
SetTimer(0.00, false);
Disable('Tick');
ZoneInfos.length = 0;
Opt_Launched = false;
// Restoring defaults on cached zeds
if (cachedZeds.Length != 0)
{
for (i=0; i<cachedZeds.Length; i++)
{
if (cachedZeds[i] == none)
{
cachedZeds.Remove(i,1);
continue;
}
cachedZeds[i].cullDistance = 0;
cachedZeds[i].bUnlit = false;
cachedZeds[i].AmbientGlow = 0;
cachedZeds[i].SoundOcclusion = Occlusion_Default;
cachedZeds[i].SoundRadius = 300;
}
cachedZeds.Length = 0;
}
// Restoring defaults on dead zeds
if (deadZeds.Length != 0)
{
for (i=0; i<deadZeds.Length; i++)
{
if (deadZeds[i] == none)
{
deadZeds.Remove(i,1);
continue;
}
deadZeds[i].LifeSpan = 8.5;
}
deadZeds.length = 0;
}
if (CurrentOptParams.bLagOff)
{
// default actor values
PolluteDefaults(true);
}
if (CurrentOptParams.bSeasonedOff)
RestoreSeasonedZeds();
GibAndGibletsTweaks(true);
}
function Timer()
{
NumSequences = NumSequences + 1;
cacheZeds(); //Get zeds on client and cache them to array
//PC.ClientMEssage("Zeds on map: " @ cachedZeds.length);
if(CurrentOptParams.new_NetSpeed > 0 && CurrentOptParams.nozed_NetSpeed > 0) //Change my netspeed
NetSpeedChanger();
if(cachedZeds.length > 0) //use cooling only if there are zeds and client "saw" them.
{
//Apply our shit
CullZedsOnMap(); //for wave based maps use KFGameReplicationInfo(myKFPC.GameReplicationInfo).MaxMonsters
}
if(deadZeds.length > 0)
{
ControlRagdolls(); //for ragdoll controlling
}
}
simulated function Tick(float Delta)
{
if(CurrentOptParams.Ticks == 0)
return;
NewTicks++;
if (NewTicks == CurrentOptParams.Ticks)
{
DetectHeadless();
}
}
// Cache Spawned Zeds
simulated function cacheZeds()
{
local KFMonster KFM;
local int i;
if (KFGameReplicationInfo(PC.GameReplicationInfo).TimeToNextWave > 0) //Don't work on trader time
{
cachedZeds.length = 0; //And destroy cached on previous wave zeds if they exist
return;
}
if (PC.AcknowledgedPawn == none && CurrentOptParams.WholeMapSearchMethod != "ZoneActors") //Do not work if we dont have pawn however zoneinfo search will work
return; //Incase of spectating with my stuff turned on
switch (CurrentOptParams.WholeMapSearchMethod)
{
case "AllActors":
ForEach PC.AcknowledgedPawn.AllActors(class'KFMonster', KFM)
{
if(KFM.Physics == PHYS_KarmaRagdoll) // cache this to dead zeds
{
deadZeds[deadZeds.length] = KFM;
}
else // cache this to alive zeds
{
if(KFM.CullDistance != CurrentOptParams.ZedCullDistance) //if we having culldistance property on a Monster => it is already been cached
{
cachedZeds[cachedZeds.length] = KFM;
}
}
}
break;
case "ZoneActors":
if(!CoolDown && PC.PlayerReplicationInfo.PlayerZone != none) //Wait for cooldown
{
for(i=0; i<ZoneInfos.Length; i++)
{
if(ZoneInfos[i] == PC.PlayerReplicationInfo.PlayerZone); //Let's start with player zone then check other zones
CurrentZone = i; //Save index
}
CoolDown = true;
}
ForEach ZoneInfos[CurrentZone].ZoneActors(class'KFMonster', KFM)
{
if (KFM.Physics == PHYS_KarmaRagdoll) //cache this to dead zeds
{
deadZeds[deadZeds.length] = KFM;
}
else //cache this to alive zeds
{
if (KFM.CullDistance != CurrentOptParams.ZedCullDistance) //if we having culldistance set on a Monster => it is already been cached
{
cachedZeds[cachedZeds.length] = KFM;
//PC.ClientMEssage("Was cached" @ CachedZeds.Length @ "zeds");
}
}
NumberOfZonesChecked++;
}
//PC.ClientMessage(cachedZeds.length @ deadZeds.length);
CurrentZone++;
if (NumberOfZonesChecked == ZoneInfos.length - 1) //back to checking player zone
{
Cooldown = false;
NumberOfZonesChecked = 0;
}
if (CurrentZone >= ZoneInfos.length)
CurrentZone = 0;
break;
case "DynamicActors":
forEach PC.AcknowledgedPawn.DynamicActors(class'KFMonster', KFM)
{
if (KFM.Physics == PHYS_KarmaRagdoll) //cache this to dead zeds
{
deadZeds[deadZeds.length] = KFM;
}
// cache this to alive zeds
else
{
// if we having culldistance set on a Monster => it is already been cached
if (KFM.CullDistance != CurrentOptParams.ZedCullDistance)
{
cachedZeds[cachedZeds.length] = KFM;
}
}
}
break;
case "RadiusActors":
foreach PC.AcknowledgedPawn.CollidingActors(class'KFMonster', KFM, CurrentOptParams.ZedSearchRadius)
{
// cache this to dead zeds
if (KFM.Physics == PHYS_KarmaRagdoll)
{
deadZeds[deadZeds.length] = KFM;
}
// cache this to alive zeds
else
{
// if we having culldistance set on a Monster => it is already been cached
if (KFM.CullDistance != CurrentOptParams.ZedCullDistance)
{
cachedZeds[cachedZeds.length] = KFM;
}
}
}
break;
}
}
// Apply our tweaks to cached zeds
simulated function CullZedsOnMap()
{
local int i;
local KFMonster KFM;
for(i = 0; i < cachedZeds.length; i++)
{
if(cachedZeds[i] == none || cachedZeds[i].Health <= 0) //Remove killed zeds
{
cachedZeds.Remove(i,1);
continue;
}
KFM = cachedZeds[i];
if(KFM == none) //none check
continue;
if(CurrentOptParams.bMonsterSpotted) //&& int(NumSequences%2)>0)
{
MonsterSpotted(KFM); //REMOVE IT
}
if(KFM.cullDistance != CurrentOptParams.ZedCullDistance)
{
KFM.cullDistance = CurrentOptParams.ZedCullDistance;
KFM.bUnlit = CurrentOptParams.UseUnlit;
KFM.AmbientGlow = CurrentOptParams.AmbientGlow;
KFM.SoundOcclusion = CurrentOptParams.SoundOcclusion;
KFM.SoundRadius = CurrentOptParams.SoundRadius;
}
}
}
simulated function MonsterSpotted(KFMOnster KFMO) //Remove IT
{
local string KFMonsterST;
if(KFMO == none)
return;
KFMonsterST = string(KFMO);
if(Instr(caps(KFMonsterST), "STALKER") != -1 && !KFMO.bSpotted)
{
KFMO.Skins[0] = Finalblend'KFX.StalkerGlow';
KFMO.Skins[1] = Finalblend'KFX.StalkerGlow';
KFMO.bUnlit = true;
}
if(Instr(caps(KFMonsterST), "GHOST") != -1 && !KFMO.bSpotted)
{
KFMO.Skins[0] = Finalblend'KFX.StalkerGlow';
KFMO.Skins[1] = Finalblend'KFX.StalkerGlow';
KFMO.bUnlit = true;
}
if(Instr(caps(KFMonsterST), "BOSS") != -1 || Instr(caps(KFMonsterST), "PAT") != -1
|| Instr(caps(KFMonsterST), "HARD") != -1)
{
if(KFMO.bCloaked == true )
{
KFMO.Skins[0] = Finalblend'KFX.StalkerGlow';
KFMO.Skins[1] = Finalblend'KFX.StalkerGlow';
KFMO.bUnlit = true;
}
if(KFMO.bHidden == true) //Remove hard pat bullshit
KFMO.bHidden = false;
}
}
simulated function NetSpeedChanger() //Netspeed changer cuz lazy me
{
if (CurrentOptParams.ConsNetSpeed) //Change netspeed
{
PC.SetNetSpeed(CurrentOptParams.New_NetSpeed); //constant netspeed
return;
}
if (KFGameReplicationInfo(PC.GameReplicationInfo).TimeToNextWave > 0 || !KFGameReplicationInfo(PC.GameReplicationInfo).bWaveInProgress)
{
PC.SetNetSpeed(CurrentOptParams.nozed_NetSpeed); // same as PC.ConsoleCommand("netspeed x"), but faster
}
else if (KFGameReplicationInfo(PC.GameReplicationInfo).bWaveInProgress
|| KFGameReplicationInfo(PC.GameReplicationInfo).MaxMonsters > 0)
{
PC.SetNetSpeed(CurrentOptParams.New_NetSpeed); // same as PC.ConsoleCommand("netspeed x"), but faster
}
}
simulated function ControlRagdolls()
{
local int i;
for (i=0; i < deadZeds.length; i++)
{
if (deadZeds[i]==none) //Avoid log-spam
{
deadZeds.Remove(i,1);
continue;
}
// PC.ClientMessage(deadZeds[i].name @ deadZeds[i].lifespan @ deadZeds[i].bCollideWorld);
if (CurrentOptParams.bNoRagdolls) //Destroy ragdolls
{
if (deadZeds[i].Destroy())
deadZeds.Remove(i,1);
else
{
deadZeds[i].bDestroyNextTick = true;
deadZeds.Remove(i,1);
}
}
else if(!deadZeds[i].bCollideWorld) //set lifespan only once
{ //vanilla dead zeds don't have bCollideWorld
deadZeds[i].Lifespan = CurrentOptParams.RagdollLifeSpan;
deadZeds[i].bCollideWorld = true; //Bodies just fall through floor without that
}
}
if (DeadZeds.length > Level.MaxRagdolls) //destroying our ragdolls with lifespan cuz sometimes engine ragdoll destroying bugging out
{
for (i=0; i < DeadZeds.length - Level.MaxRagdolls; i++)
if (DeadZeds[DeadZeds.length-1].Destroy()) //Destroying last ragdolls in our array
DeadZeds.Remove(DeadZeds.length-1,1); //Removing none references
}
}
//================================Firebug shit
simulated function FirebugDisabler() //Some tweaks to burn emitters
{
local class<Emitter> E;
local int i;
if (LowGore)
{
//Some tweaks to Alt burn emitter
class'KFAltMonsterFlame'.default.Emitters[0] = class'KFBurnEffect_FPS'.default.Emitters[0];
//light
class'KFAltMonsterFlame'.default.LightRadius = LC.LightRadius;
class'KFAltMonsterFlame'.default.LightType = LC.LightType;
class'KFAltMonsterFlame'.default.LightBrightness = LC.LightBrightness;
class'KFAltMonsterFlame'.default.LightHue = LC.LightHue;
class'KFAltMonsterFlame'.default.LightSaturation = LC.LightSaturation;
class'KFAltMonsterFlame'.default.bDynamicLight = LC.bDynamicLight;
class'KFAltMonsterFlame'.default.bSpecialLit = LC.bSpecialLit;
}
if (LagEmitters.length == 0)
return;
//Lighting tweaks (from pulse to steady light cuz of fps drops when using multiple pulse lights)
for (i=0;i<LagEmitters.length;i++)
{
E = GetEmitterClassFromString(LagEmitters[i]);
if (E==none)
continue;
if (LC.LightRadius >= 0)
E.default.LightRadius = LC.LightRadius;
E.default.LightType = LC.LightType;
if (LC.LightBrightness >= 0)
E.default.LightBrightness = LC.LightBrightness;
if (LC.LightHue >= 0)
E.default.LightHue = LC.LightHue;
if (LC.LightSaturation >= 0)
E.default.LightSaturation = LC.LightSaturation;
E.default.bDynamicLight = LC.bDynamicLight;
E.default.bSpecialLit = LC.bSpecialLit;
}
// Some tweaks to Burn emitter
class'KFMonsterFlame'.default.LightRadius = LC.LightRadius;
class'KFMonsterFlame'.default.LightType = LC.LightType;
class'KFMonsterFlame'.default.LightBrightness = LC.LightBrightness;
class'KFMonsterFlame'.default.LightHue = LC.LightHue;
class'KFMonsterFlame'.default.LightSaturation = LC.LightSaturation;
class'KFMonsterFlame'.default.bDynamicLight = LC.bDynamicLight;
class'KFMonsterFlame'.default.bSpecialLit = LC.bSpecialLit;
}
//=======================================================for preloading assets hax ofc
simulated function LoadZedsAssets(byte Asset)
{
local KFMonster KFM;
local array<string> ZedClassNames;
// Standard
if (Asset == 0)
ZedClassNames = KFMonsterClassNames_Standard;
// Circus
else if (Asset == 1)
ZedClassNames = KFMonsterClassNames_Circus;
// Hillbilly
else if (Asset == 2)
ZedClassNames = KFMonsterClassNames_Halloween;
// XMAS
else if (Asset == 2)
ZedClassNames = KFMonsterClassNames_XMas;
// Custom
else if (Asset == 4)
ZedClassNames = CustomZeds;
LoadVanillaMonster(ZedClassNames);
log(">>> a_MonsterOptimizer -> LoadZedsAssets() called with asset IDX - " $ Asset);
// Kill locally spawned zeds, hehehe
forEach DynamicActors (class'KFMonster', KFM)
KFM.Suicide();
}
// TWI summon function
final private function LoadVanillaMonster(array<string> ClassNames)
{
local class<actor> NewClass;
local vector SpawnLoc;
local int i;
for (i = 0; i < ClassNames.length; i++)
{
NewClass = class<actor>(DynamicLoadObject(ClassNames[i], class'class', true));
if (NewClass != none && PC != none)
{
SpawnLoc = PC.Location;
PC.spawn(NewClass,,, SpawnLoc);
}
}
}
// ======================================================= for preloading assets hax ofc end
// Simple function that copy All particle emitter inline set from source to target
// return -1 if error
// If Target has more emitters that source, emitters will be nopped if NoneFlag or left intact
simulated function int LoadAndPolluteGoreEmitters(string sourceName, string targetName, optional bool NoneFlag)
{
local class<Emitter> Source;
local class<Emitter> Target;
local int k;
Source = class<Emitter>(DynamicLoadObject(sourceName, class'class', true));
Target = class<Emitter>(DynamicLoadObject(targetName, class'class', true));
if (Source == none || Target == none)
return -1;
for (k = 0; k < Target.default.Emitters.Length; k++)
{
// if NoneFlag overwrite particle emitters with nones
if (Source.default.Emitters[k] == none && NoneFlag)
Target.default.Emitters[k] = none;
// stop on first none reference
else if (Source.default.Emitters[k] == none && !NoneFlag)
break;
Target.default.Emitters[k] = Source.default.Emitters[k];
}
return 1;
}
// Load emitter defaults from backup classes
simulated function LoadGoreEmitters(string targetName, byte EmitterNumber)
{
local int i;
local Class<Emitter> Target;
local array<class <Emitter> > SourceArray;
if (BackupGore.length == 0 && EmitterNumber == 0)
{
BackupGore[0] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[0], class'class', true));
BackupGore[1] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[1], class'class', true));
BackupGore[2] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[2], class'class', true));
BackupGore[3] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[3], class'class', true));
}
if (OptGore.length == 0 && EmitterNumber == 1)
{
OptGore[0] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[4], class'class', true));
OptGore[1] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[5], class'class', true));
OptGore[2] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[6], class'class', true));
OptGore[3] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[7], class'class', true));
}
if (LowGoreE.length == 0 && EmitterNumber == 2)
{
LowGoreE[0] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[8], class'class', true));
LowGoreE[1] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[9], class'class', true));
LowGoreE[2] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[10], class'class', true));
LowGoreE[3] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[11], class'class', true));
}
if (NoGore.length == 0 && EmitterNumber == 3)
{
NoGore[0] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[12], class'class', true));
NoGore[1] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[13], class'class', true));
NoGore[2] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[14], class'class', true));
NoGore[3] = class<Emitter>(DynamicLoadObject(TWIGoreBackup[15], class'class', true));
}
Target = class<Emitter>(DynamicLoadObject(targetName, class'class', true));
if (Target == none )
return;
switch (EmitterNumber)
{
case 0:
SourceArray = BackupGore;
break;
case 1:
SourceArray = OptGore;
break;
case 2:
SourceArray = LowGoreE;
break;
case 3:
SourceArray = NoGore;
break;
}
for (i = 0; i < SourceArray.length; i++)
{
if (Instr(Target, Mid(SourceArray[i],Instr(SourceArray[i], "_") + 1)) != -1)
{
LoadAndPolluteGoreEmitters(string(SourceArray[i]), string(target));
target.default.bHidden = SourceArray[i].default.bHidden;
target.default.bUnlit = SourceArray[i].default.bUnlit;
target.default.LifeSpan = SourceArray[i].default.LifeSpan;
target.default.Style = SourceArray[i].default.Style;
target.default.bDirectional = SourceArray[i].default.bDirectional;
break;
}
else
continue;
}
// unload our classes
BackupGore.length = 0;
OptGore.length = 0;
LowGoreE.length = 0;
NoGore.length = 0;
}
// Restore emitters from backup
simulated function RestoreGoreEmitterFromBackups()
{
local int i, k;
local Class<Emitter> CLEmitter;
if (EMP_back.length==0)
return;
for (i=0;i<EMP_back.length;i++)
{
CLEmitter = class<Emitter>(DynamicLoadObject(EMP_back[i].ClassName, class'class', true));
if(CLEmitter==none)
continue;
for (k=0; k < CLEmitter.default.Emitters.Length; k++)
{
CLEmitter.default.Emitters[k].Disabled = EMP_back[i].CEMP[k].Disabled;
CLEmitter.default.Emitters[k].UseCollision = EMP_back[i].CEMP[k].UseCollision;
CLEmitter.default.Emitters[k].AcceptsProjectors = EMP_back[i].CEMP[k].AcceptsProjectors;
}
}
}
//Reset flag indicates that emitter should reset to default parameters
simulated function AnotherGoreEmitterLoad(string EmitterToLoad, EMB EmitterPrefs)
{
/*
var EMP_backups EMP_backSingle; //for backuping emitters properties, single emitter
var array<EMP_backups> EMP_back; //for backuping emitters properties, emitters array
*/
local Class<Emitter> CLEmitter;
local int k;
CLEmitter = class<Emitter>(DynamicLoadObject(EmitterToLoad, class'class', true));
if(CLEmitter==none)
return;
// backuping our emitters
EMP_backSingle.ClassName = string(CLEmitter);
EMP_backSingle.bHidden = CLEmitter.default.bHidden;
EMP_backSingle.bUnlit = CLEmitter.default.bUnlit;
EMP_backSingle.Lifespan = CLEmitter.default.LifeSpan;
for(k=0; k < CLEmitter.default.Emitters.Length; k++) //Backuping particle emitters preferences
{
EMP_backSingle.CEMP[k].ClassName = string(CLEmitter.default.Emitters[k]);
EMP_backSingle.CEMP[k].Disabled = CLEmitter.default.Emitters[k].Disabled;
EMP_backSingle.CEMP[k].UseCollision = CLEmitter.default.Emitters[k].UseCollision;
EMP_backSingle.CEMP[k].AcceptsProjectors = CLEmitter.default.Emitters[k].AcceptsProjectors;
}
if(EMP_back.length !=0)
{
EMP_back.length = EMP_back.length + 1;
EMP_back[EMP_back.length] = EMP_backSingle;
}
else
EMP_back[EMP_back.length] = EMP_backSingle;
// Apply our tweaks
CLEmitter.default.bHidden = EmitterPrefs.bHidden;
CLEmitter.default.bUnlit = EmitterPrefs.bUnlit;
CLEmitter.default.LifeSpan = EmitterPrefs.Lifespan;
for(k=0; k < CLEmitter.default.Emitters.Length; k++)
{
CLEmitter.default.Emitters[k].UseCollision = EmitterPrefs.UseCollision;
ClEmitter.default.Emitters[k].Disabled = EmitterPrefs.Disabled; //Disable all particle emitters
ClEmitter.default.Emitters[k].AcceptsProjectors = EmitterPrefs.AcceptsProjectors;
}
}
//Rewrite this and make this shit dynamic
//=====================================================================
simulated function AddStandardGorePresets()
{
local int i,k;
local class<Emitter> ClEmitter;
Gore_Preset.PresetName = "OPTIMIZED_TWI";
Gore_Preset.PresetDescription = "Optimized TWI shit...";
Gore_Preset.EmittersToLoad.Insert(0, KFMonsterGibEmitters.length);
for (i=0; i< KFMonsterGibEmitters.length; i++)
{
Gore_Preset.EmittersToLoad[i].ClassName = KFMonsterGibEmitters[i];
Gore_Preset.EmittersToLoad[i].bHidden = false;
Gore_Preset.EmittersToLoad[i].bUnlit = true;
Gore_Preset.EmittersToLoad[i].LifeSpan = 5;
CLEmitter = class<Emitter>(DynamicLoadObject(KFMonsterGibEmitters[i], class'class', true));
// if (CLEmitter == none)
// PC.ClientMessage("OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" @ KFMonsterGibEmitters[i]);
Gore_Preset.EmittersToLoad[i].CEMP.Insert(0, CLEmitter.default.Emitters.Length);
for (k=0; k < CLEmitter.default.Emitters.Length; k++) //Editing particle emitters
{
Gore_Preset.EmittersToLoad[i].CEMP[k].ClassName = string(CLEmitter.default.Emitters[k]);
Gore_Preset.EmittersToLoad[i].CEMP[k].Disabled = false;
if (int(CLEmitter.default.Emitters[k].InitialParticlesPerSecond / CLEmitter.default.Emitters[k].MaxParticles) > 350) //not fucking 0.00000001
Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond = float(CLEmitter.default.Emitters[k].MaxParticles * 200); //0.01 ms to spawn
else
Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond = CLEmitter.default.Emitters[k].InitialParticlesPerSecond; //else let's save old value
Gore_Preset.EmittersToLoad[i].CEMP[k].UseCollision = CLEmitter.default.Emitters[k].UseCollision;
Gore_Preset.EmittersToLoad[i].CEMP[k].AcceptsProjectors = false;
}
}
Gore_Presets[0] = Gore_Preset;
Gore_Preset.PresetName = "NO_GORE";
Gore_Preset.PresetDescription = "No gore at all. Disables all emitters.";
Gore_Preset.EmittersToLoad.Insert(0, KFMonsterGibEmitters.length);
for (i=0; i< KFMonsterGibEmitters.length; i++)
{
Gore_Preset.EmittersToLoad[i].ClassName = KFMonsterGibEmitters[i];
Gore_Preset.EmittersToLoad[i].bHidden = true;
Gore_Preset.EmittersToLoad[i].bUnlit = true;
Gore_Preset.EmittersToLoad[i].LifeSpan = 0.5;
CLEmitter = class<Emitter>(DynamicLoadObject(KFMonsterGibEmitters[i], class'class', true));
Gore_Preset.EmittersToLoad[i].CEMP.Insert(0, CLEmitter.default.Emitters.Length);
for (k=0; k < CLEmitter.default.Emitters.Length; k++) //Editing particle emitters
{
Gore_Preset.EmittersToLoad[i].CEMP[k].ClassName = string(CLEmitter.default.Emitters[k]);
Gore_Preset.EmittersToLoad[i].CEMP[k].Disabled = true;
Gore_Preset.EmittersToLoad[i].CEMP[k].UseCollision = false;
Gore_Preset.EmittersToLoad[i].CEMP[k].AcceptsProjectors = false;
}
}
Gore_Presets[1] = Gore_Preset;
Gore_Preset.PresetName = "LOW_GORE";
Gore_Preset.PresetDescription = "Low gore.";
Gore_Preset.EmittersToLoad.Insert(0, KFMonsterGibEmitters.length);
for (i=0; i< KFMonsterGibEmitters.length; i++)
{
Gore_Preset.EmittersToLoad[i].ClassName = KFMonsterGibEmitters[i];
Gore_Preset.EmittersToLoad[i].bHidden = false;
Gore_Preset.EmittersToLoad[i].bUnlit = true;
Gore_Preset.EmittersToLoad[i].LifeSpan = 5;
CLEmitter = class<Emitter>(DynamicLoadObject(KFMonsterGibEmitters[i], class'class', true));
Gore_Preset.EmittersToLoad[i].CEMP.Insert(0, CLEmitter.default.Emitters.Length);
for (k=0; k < CLEmitter.default.Emitters.Length; k++) //Editing particle emitters
{
Gore_Preset.EmittersToLoad[i].CEMP[k].ClassName = string(CLEmitter.default.Emitters[k]);
Gore_Preset.EmittersToLoad[i].CEMP[k].Disabled = false;
if (int(CLEmitter.default.Emitters[k].InitialParticlesPerSecond / CLEmitter.default.Emitters[k].MaxParticles) > 350) //not fucking 0.00000001
Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond = float(CLEmitter.default.Emitters[k].MaxParticles * 200); //0.01 ms to spawn
else
Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond = CLEmitter.default.Emitters[k].InitialParticlesPerSecond; //else let's save old value
Gore_Preset.EmittersToLoad[i].CEMP[k].UseCollision = false;
Gore_Preset.EmittersToLoad[i].CEMP[k].AcceptsProjectors = false;
}
}
Gore_Presets[2] = Gore_Preset;
Gore_Preset.PresetName = "TWI";
Gore_Preset.PresetDescription = "Just TWI shit...";
Gore_Preset.EmittersToLoad.Insert(0, KFMonsterGibEmitters.length);
for (i=0; i< KFMonsterGibEmitters.length; i++)
{
CLEmitter = class<Emitter>(DynamicLoadObject(KFMonsterGibEmitters[i], class'class', true));
Gore_Preset.EmittersToLoad[i].ClassName = KFMonsterGibEmitters[i];
Gore_Preset.EmittersToLoad[i].bHidden = false;
Gore_Preset.EmittersToLoad[i].bUnlit = false;
Gore_Preset.EmittersToLoad[i].LifeSpan = CLEmitter.default.Lifespan;
Gore_Preset.EmittersToLoad[i].CEMP.Insert(0, CLEmitter.default.Emitters.Length);
for (k=0; k < CLEmitter.default.Emitters.Length; k++) //Editing particle emitters
{
Gore_Preset.EmittersToLoad[i].CEMP[k].ClassName = string(CLEmitter.default.Emitters[k]);
Gore_Preset.EmittersToLoad[i].CEMP[k].Disabled = false;
Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond = CLEmitter.default.Emitters[k].InitialParticlesPerSecond; //else let's save old value
Gore_Preset.EmittersToLoad[i].CEMP[k].UseCollision = CLEmitter.default.Emitters[k].UseCollision;
Gore_Preset.EmittersToLoad[i].CEMP[k].AcceptsProjectors = false;
}
}
Gore_Presets[3] = Gore_Preset;
}
simulated function ApplyStandardGorePresets(string SetPresetName)
{
local int i,k, l;
local class<Emitter> ClEmitter;
for (l=0; l < Gore_Presets.length; l++)
{
if (Gore_Presets[l].PresetName == SetPresetName)
{
Gore_Preset = Gore_Presets[l];
for (i=0; i< KFMonsterGibEmitters.length; i++)
{
if (Gore_Preset.EmittersToLoad[i].ClassName == KFMonsterGibEmitters[i])
{
CLEmitter = class<Emitter>(DynamicLoadObject(KFMonsterGibEmitters[i], class'class', true));
CLEmitter.default.bHidden = Gore_Preset.EmittersToLoad[i].bHidden;
CLEmitter.default.bUnlit = Gore_Preset.EmittersToLoad[i].bUnlit;
CLEmitter.default.LifeSpan = Gore_Preset.EmittersToLoad[i].LifeSpan;
//PC.ClientMessage("Hidden is" @ CLEmitter.default.bHidden @ "Unlit is" @ CLEmitter.default.bUnlit @ "Lifespan is" @ CLEmitter.default.LifeSpan);
for (k=0; k < CLEmitter.default.Emitters.Length; k++) //Editing particle emitters
{
CLEmitter.default.Emitters[k].Disabled = Gore_Preset.EmittersToLoad[i].CEMP[k].Disabled;
//PC.ClientMessage("Disabled is" @ Gore_Preset.EmittersToLoad[i].CEMP[k].Disabled @ "on" @ CLEmitter.default.Emitters[k]);
CLEmitter.default.Emitters[k].InitialParticlesPerSecond = Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond;
//PC.ClientMessage("Initial particles are" @ Gore_Preset.EmittersToLoad[i].CEMP[k].InitialParticlesPerSecond);
CLEmitter.default.Emitters[k].UseCollision = Gore_Preset.EmittersToLoad[i].CEMP[k].UseCollision;
//PC.ClientMessage(Gore_Preset.EmittersToLoad[i].CEMP[k].UseCollision);
CLEmitter.default.Emitters[k].AcceptsProjectors = Gore_Preset.EmittersToLoad[i].CEMP[k].AcceptsProjectors;
//PC.ClientMessage(Gore_Preset.EmittersToLoad[i].CEMP[k].AcceptsProjectors);
}
break;
}
}
break;
}
else
continue;
}
}
//=====================================================================
//Some gore-related emitter tweaks
simulated function OptimizeGore()
{
//local int i;
GibAndGibletsTweaks(false);
/*
if(CurrentOptParams.UserSettingsToEmitters) //load user settings
{
for (i=0; i < KFMonsterGibEmitters.length; i++)
{
AnotherGoreEmitterLoad(KFMonsterGibEmitters[i], User_EMPS); //Load user settings
}
}
*/
if(Gore_Presets.length == 0)
AddStandardGorePresets();
ApplyStandardGorePresets(CurrentOptParams.GoreLevel); //Apply our gore parameters
switch(CurrentOptParams.GoreLevel)
{
case "OPTIMIZED_TWI":
LoadGoreEmitters(TWIGibEmitters[0], 1);
LoadGoreEmitters(TWIGibEmitters[1], 1);
LoadGoreEmitters(TWIGibEmitters[2], 1);
LoadGoreEmitters(TWIGibEmitters[3], 1);
break;
case "TWI":
LoadGoreEmitters(TWIGibEmitters[0], 0);
LoadGoreEmitters(TWIGibEmitters[1], 0);
LoadGoreEmitters(TWIGibEmitters[2], 0);
LoadGoreEmitters(TWIGibEmitters[3], 0);
break;
case "NO_GORE": //No gore preset
LoadGoreEmitters(TWIGibEmitters[0], 3);
LoadGoreEmitters(TWIGibEmitters[1], 3);
LoadGoreEmitters(TWIGibEmitters[2], 3);
LoadGoreEmitters(TWIGibEmitters[3], 3);
break;
case "LOW_GORE":
LoadGoreEmitters(TWIGibEmitters[0], 2);
LoadGoreEmitters(TWIGibEmitters[1], 2);
LoadGoreEmitters(TWIGibEmitters[2], 2);
LoadGoreEmitters(TWIGibEmitters[3], 2);
break;
case "GORY!":
break;
case "BLOOD FOR THE BLOOD GOD!":
break;
}
}
// Tweaks for gibz and giblets
// Pollute gib classes, flag reset to default parameters
simulated function PolluteGibClasses(string GibGlass,optional bool Reset)
{
local class<KFGib> KFGib;
KFGib = GetGibletsClassFromString(GibGlass);
if (KFGib==none)
return;
if (!Reset)
{
KFGib.default.bHidden = CurrentOptParams.bHideGibs;
KFGib.default.bUnlit = CurrentOptParams.bUnlitGibs;
KFGib.default.LifeSpan= CurrentOptParams.GibsLifespan;
if (CurrentOptParams.GibUseDeferRendering)
{
KFGib.default.Style = STY_Additive; //Enable defer rendering
KFGib.default.bDeferRendering = true;
}
KFGib.default.MaxLights = CurrentOptParams.GibMaxLights;
KFGib.default.bUseCollisionStaticMesh= CurrentOptParams.GibUseCollisionStaticMesh;
KFGib.default.bAcceptsProjectors = CurrentOptParams.GibAcceptProjectors;
KFGib.default.bStaticLighting = CurrentOptParams.GibStaticLighting;
}
else
{
KFGib.default.bHidden = false;
KFGib.default.bUnlit = false;
KFGib.default.LifeSpan= 6.0;
if (CurrentOptParams.GibUseDeferRendering)
{
KFGib.default.Style = STY_Normal;
}
KFGib.default.MaxLights = 4;
KFGib.default.bUseCollisionStaticMesh= true;
KFGib.default.bAcceptsProjectors = true;
KFGib.default.bStaticLighting = false;
}
}
simulated function PolluteGibletsClasses(string GibletGlass,optional bool Reset)
{
local class<SeveredAppendage> KFSevered;
KFSevered = GetGibClassFromString(GibletGlass);
if (KFSevered==none)
return;
if (!Reset)
{
KFSevered.default.bHidden = CurrentOptParams.bHideGiblets;
KFSevered.default.bUnlit = CurrentOptParams.bUnlitGiblets;
KFSevered.default.LifeSpan = CurrentOptParams.GibletsLifespan;
if (CurrentOptParams.GibletsUseDeferRendering)
{
KFSevered.default.Style = STY_Additive; //Enable defer rendering
KFSevered.default.bDeferRendering = true;
}
KFSevered.default.MaxLights = CurrentOptParams.GibletsMaxLights;
KFSevered.default.bUseCollisionStaticMesh= CurrentOptParams.GibletsUseCollisionStaticMesh;
KFSevered.default.bAcceptsProjectors = CurrentOptParams.GibletsAcceptProjectors;
KFSevered.default.bStaticLighting = CurrentOptParams.GibletsStaticLighting;
}
else
{
KFSevered.default.bHidden = false;
KFSevered.default.bUnlit = false;
KFSevered.default.LifeSpan = 8.0;
if (CurrentOptParams.GibletsUseDeferRendering)
{
KFSevered.default.Style = STY_Normal; //Disable defer rendering
KFSevered.default.bDeferRendering = true;
}
KFSevered.default.MaxLights = 4;
KFSevered.default.bUseCollisionStaticMesh= false;
KFSevered.default.bAcceptsProjectors = true;
KFSevered.default.bStaticLighting = false;
}
}
simulated function GibAndGibletsTweaks(bool Reset)
{
local int i;
if (CurrentOptParams.bAdvancedGiblets)
{
for (i=0; i<KFMonsterGibletsClassNames.length; i++)
{
PolluteGibletsClasses(KFMonsterGibletsClassNames[i], Reset);
}
}
if (CurrentOptParams.bAdvancedGibs)
{
for (i=0; i<KFMonsterGibClassNames.length; i++)
{
PolluteGibClasses(KFMonsterGibClassNames[i], Reset);
}
}
}
//Load and pollute default monster classes
simulated function LoadMonsters(string MonsterClassToLoad, optional bool Reset)
{
local class<KFMonster> KFM;
if(!Reset)
{
KFM = GetMonsterClassFromString(MonsterClassToLoad);
if(KFM==none)
return;
KFM.default.cullDistance = CurrentOptParams.ZedCullDistance;
KFM.default.bUnlit = CurrentOptParams.useUnlit;
KFM.default.AmbientGlow =CurrentOptParams.AmbientGlow;
KFM.default.SoundOcclusion = CurrentOptParams.SoundOcclusion;
KFM.default.SoundRadius = CurrentOptParams.SoundRadius;
}
else
{
KFM.default.cullDistance = 0;
KFM.default.bUnlit = false;
KFM.default.AmbientGlow = 0;
KFM.default.SoundOcclusion = Occlusion_Default;
KFM.default.SoundRadius = 300;
}
}
//Pollute default zed classes and detect gametype
simulated function PolluteDefaults(bool Reset)
{
local int i;
for(i=0; i<KFMonsterClassNames_Standard.length; i++)
{
if (CurrentOptParams.bStandard) //Loading standard classes
{
LoadMonsters(KFMonsterClassNames_Standard[i], Reset);
}
else if (CurrentOptParams.bCircus) //Loading circus classes
{
LoadMonsters(KFMonsterClassNames_Circus[i], Reset);
}
else if (CurrentOptParams.bXmas) //Loading xmas classes
{
LoadMonsters(KFMonsterClassNames_XMas[i], Reset);
}
else if (CurrentOptParams.bHillBilly) //Loading standard classes
{
LoadMonsters(KFMonsterClassNames_Halloween[i], Reset);
}
}
if(Instr(CAPS(Level.GRI.GameClass), "SCRN")!=-1) //Scrn gametype custom zeds
{
for (i=0; i<CustomZeds.length; i++)
{
LoadMonsters(CustomZeds[i], Reset);
}
}
if(Instr(CAPS(Level.GRI.GameClass), "NICE")!=-1) //NicePack.NiceGameType
{
for(i=0; i<NiceZeds.length; i++)
{
LoadMonsters(NiceZeds[i], Reset);
}
}
}
//=======================================Seasoned zeds remover
simulated function RemoveSeasonedZeds()
{
/*
CurrentOptParams.bStandard
*/
if (CurrentOptParams.bCircus)
ReplaceZedsDefaults(KFMonsterClassNames_Circus, KFMonsterClassNames_Standard);
if (CurrentOptParams.bXmas)
ReplaceZedsDefaults(KFMonsterClassNames_Halloween, KFMonsterClassNames_Standard);
if (CurrentOptParams.bHillBilly)
ReplaceZedsDefaults(KFMonsterClassNames_XMas, KFMonsterClassNames_Standard);
}
//===================================Replaces zed properties sets with KFMReplace class properties sets
simulated function ReplaceZedsDefaults(array<string> KFMonsterClassNames, array<string> KFMReplace)
{
local int i,k;
local class<KFMonster> KFM, ReplaceKFM;
local string MeshName;
//OFC some bullshit first...
/*Shaders. Need to re-do this...
class'ZombieClot_HALLOWEEN'.default.ClotSkins[0] = shader'Chaos_WeaponPack_T.Clot_standard_shader';
class'ZombieClot_HALLOWEEN'.default.ClotSkins[1] = shader'Chaos_WeaponPack_T.Clot_standard_shader';
class'ZombieClot_HALLOWEEN'.default.ClotSkins[2] = shader'Chaos_WeaponPack_T.Clot_standard_shader';
class'ZombieClot_HALLOWEEN'.default.ClotSkins[3] = shader'Chaos_WeaponPack_T.Clot_standard_shader';
class'ZombieClot_HALLOWEEN'.default.ClotSkins[4] = shader'Chaos_WeaponPack_T.Clot_standard_shader';
class'ZombieClot_HALLOWEEN'.default.ClotSkins[5] = shader'Chaos_WeaponPack_T.Clot_standard_shader';
*/
if (KFMonsterClassNames.length != KFMReplace.length)
return;
class'ZombieGoreFast_CIRCUS'.default.bHeadGibbed=false; //go fuck your mouth with your circus shit
for (i=0; i<KFMonsterClassNames.length; i++)
{
KFM = GetMonsterClassFromString(KFMonsterClassNames[i]); //Get monster class to pollute
ReplaceKFM = GetMonsterClassFromString(KFMReplace[i]); //load class replacer
if (KFM == none || ReplaceKFM == none) // if none - continue
continue;
MeshName = string(ReplaceKFM.default.Mesh); //save mesh name
KFM.static.UpdateDefaultMesh(SkeletalMesh(DynamicLoadObject(MeshName, Class'SkeletalMesh', true))); //replace default skeletal mesh
for(k=0;k<KFM.default.Skins.Length;k++) //Reloading skins
{
KFM.default.Skins[k] = ReplaceKFM.default.Skins[k];
}
KFM.default.DetachedArmClass = ReplaceKFM.default.DetachedArmClass; //Reloading gore-related shit
KFM.default.DetachedLegClass = ReplaceKFM.default.DetachedLegClass;
KFM.default.DetachedHeadClass = ReplaceKFM.default.DetachedHeadClass;
KFM.default.HitSound[0] = ReplaceKFM.default.HitSound[0]; //Static arrays...
KFM.default.ChallengeSound[0] = ReplaceKFM.default.ChallengeSound[0]; //...
KFM.default.ChallengeSound[1] = ReplaceKFM.default.ChallengeSound[1];
KFM.default.ChallengeSound[2] = ReplaceKFM.default.ChallengeSound[2];
KFM.default.ChallengeSound[3] = ReplaceKFM.default.ChallengeSound[3];
KFM.default.AmbientSound = ReplaceKFM.default.AmbientSound; //Replacing ambient sounds
KFM.default.MoanVoice = ReplaceKFM.default.MoanVoice; //Replacing moan voice aka idle moaning sounds
KFM.default.DeathSound[0]=ReplaceKFM.default.DeathSound[0]; //...
KFM.default.DeathSound[1]=ReplaceKFM.default.DeathSound[1];
KFM.default.JumpSound=ReplaceKFM.default.JumpSound;
KFM.default.MeleeAttackHitSound=ReplaceKFM.default.MeleeAttackHitSound;
}
}
simulated function RestoreSeasonedZeds(){}
// Detect headless zeds for LowGore decaps
simulated function DetectHeadless()
{
local int i;
local KFMonster KFM;
NewTicks=0;
if (!LowGore)
return;
for (i = 0; i < cachedZeds.length; i++)
{
KFM = cachedZeds[i];
if (KFM == none)
continue;
if ((KFM.bDecapitated && KFM.Health <= 0) || KFM.bDecapitated)
{
// CuteDecapFX undone
KFM.NeckRot.Yaw = 0;
KFM.NeckRot.Roll = 0;
KFM.NeckRot.Pitch = 0;
KFM.SetBoneRotation('neck', KFM.NeckRot);
// Using decap function for melee weapons cuz no fps drops.
KFM.SpecialHideHead();
}
}
}
//==============String to class conversion
simulated function class<KFGib> GetGibletsClassFromString(string String)
{
//for conversion from string to class reference
return class<KFGib>(DynamicLoadObject(String, class'class', true));
}
simulated function class<SeveredAppendage> GetGibClassFromString(string String)
{
//for conversion from string to class reference
return class<SeveredAppendage>(DynamicLoadObject(String, class'class', true));
}
simulated function class<KFMonster> GetMonsterClassFromString(string String)
{
//for conversion from string to class reference
return class<KFMonster>(DynamicLoadObject(String, class'class', true));
}
//==============String to class conversion
simulated function class<Emitter> GetEmitterClassFromString(string String)
{
//for conversion from string to class reference
return class<Emitter>(DynamicLoadObject(String, class'class', true));
}
// self cleanup
function Termination()
{
pc = none;
cachedZeds.length = 0;
deadZeds.length = 0;
ZoneInfos.length = 0;
Zone = none;
CurrentOptParams = none;
LC = none;
EMP_backSingle = none;
EMP_back.length = 0;
User_EMPS = none;
Gore_Presets.length = 0;
Gore_Preset = none;
BackupGore.length = 0;
OptGore.length = 0;
LowGoreE.length = 0;
NoGore.length = 0;
super.Termination();
}
defaultproperties
{
bUnlit=True
}