KFStatOutput
This is my stat generator for the killing floor weapon pages. --Benjamin (talk) 20:42, 11 October 2012 (EDT)
//============================================================================= // Weapon stat generator 12-October-2012 Benjamin // // KNOWN ISSUES // // * Cannot detect where different fire modes share the same // ammo (boomstick) // // * Cannot detect penetration for all weapons. // // * (!) Cannot obtain hunting shotgun (or crossbow) reload speed // // INFO // // All instant-fire weapons rely on the DamageType for the head shot // multiplier. // // Any projectiles that derive from ShotgunBullet.uc use 'HeadShotDamageMult' // as the head damage multiplier. The following projectiles implement their own // with the same name: // // CrossbowArrow.uc // HuskGunProjectile.uc // M99Bullet.uc // // NOTES // // (1) Certain classes don't use AmmoPerFire: MP7MAltFire, M7A3MAltFire // (2) Hardcoded penetration values: Deagle, MK23, 44Magnum // * Also crossbow and M99 // (3) Weapons only have a single ReloadRate stat //============================================================================= class KFStatOutputMut extends Mutator; var class<KFWeaponPickup> Pickup; var class<KFWeapon> Weapon; var class<WeaponFire> Fire[2]; function bool IsTrueFire(class<WeaponFire> Fire) { if (Fire.Name == 'NoFire' || Fire.Name == 'ShotgunLightFire' || Fire.Name == 'SingleALTFire' ) return false; return true; } function bool IsMeleeFire(class<WeaponFire> Fire) { if (Fire == none) return false; if (class<KFMeleeFire>(Fire) != none) return true; return false; } function bool IgnoresLoad(class<WeaponFire> Fire) { if (class<MP7MAltFire>(Fire) != none || class<M7A3MAltFire>(Fire) != none) return true; return false; } function OutputStatNum(string Title, float Stat, optional float AltStat) { OutputStat(Title, string(Stat), string(AltStat)); } function OutputStat(string Title, string Stat, optional string AltStat) { local int A, x; // Adjust stat name Title $= ":"; A = Len(Title); if (A < 14) { for (x = 0; x < 14 - A; x++) Title $= " "; } if (Fire[1] != none && AltStat != "") Log(Title $ Stat @ "(" $ AltStat $ ")"); else Log(Title $ Stat); } function PostBeginPlay() { local string Name; local string Perk; local int Cost; local int Weight; local int Capacity[2]; local int MagazineSize[2]; local float FireRate[2]; local float ReloadSpeed[2]; local float Spread[2]; local int Damage[2]; local float DamageRadius[2]; local float HeadMultiplier[2]; local int Pellets[2]; local int MaxPens[2]; local float PenReduction[2]; local int i, x; // Main loop for (i = 0; class'KFLevelRules'.default.ItemForSale[i] != none; i++) { Pickup = class<KFWeaponPickup>(class'KFLevelRules'.default.ItemForSale[i]); if (Pickup != none) { Weapon = class<KFWeapon>(Pickup.default.InventoryType); if (Weapon != none) { for (x = 0; x < 2; x++) { if (Weapon.default.FireModeClass[x] != none && IsTrueFire(Weapon.default.FireModeClass[x])) Fire[x] = Weapon.default.FireModeClass[x]; else Fire[x] = none; } GetName(Name); GetPerk(Perk); GetCost(Cost); GetWeight(Weight); GetCapacity(Capacity); GetMagazineSize(MagazineSize); GetFireRate(FireRate); GetReloadSpeed(ReloadSpeed); GetSpread(Spread); GetDamage(Damage); GetDamageRadius(DamageRadius); GetHeadMultiplier(HeadMultiplier); GetPellets(Pellets); GetMaxPens(MaxPens); GetPenReduction(PenReduction); OutputStat ("Name", Name); OutputStat ("Perk", Perk); OutputStatNum("Cost", Cost); OutputStatNum("Weight", Weight); OutputStatNum("Capacity", Capacity[0], Capacity[1]); OutputStatNum("Magazine", MagazineSize[0], MagazineSize[1]); OutputStatNum("Fire rate", FireRate[0], FireRate[1]); OutputStatNum("Reload sp", ReloadSpeed[0], ReloadSpeed[1]); OutputStatNum("Spread", Spread[0], Spread[1]); OutputStatNum("Damage", Damage[0], Damage[1]); OutputStatNum("Radius", DamageRadius[0], DamageRadius[0]); OutputStatNum("Head", HeadMultiplier[0], HeadMultiplier[1] ); OutputStatNum("Pellets", Pellets[0], Pellets[1]); OutputStatNum("Max pens", MaxPens[0], MaxPens[1]); OutputStatNum("Pen reduc", PenReduction[0], PenReduction[1]); Log(""); } } } Destroy(); } /////////////////////////////////////////////////////////////////////////////// // STAT CALCULATION /////////////////////////////////////////////////////////////////////////////// function GetName(out string Name) { Name = Pickup.default.ItemName; } function GetPerk(out string Perk) { Perk = KFGameType(Level.Game).default. LoadedSkills[Pickup.default.CorrespondingPerkIndex].default.VeterancyName; } function GetCost(out int Cost) { Cost = Pickup.default.Cost; } function GetWeight(out int Weight) { Weight = Pickup.default.Weight; } function GetCapacity(out int Capacity[2], optional int Index) { Capacity[Index] = 0; if (Index == 0) GetCapacity(Capacity, 1); if (Fire[Index] != none && !IsMeleeFire(Fire[Index]) && Fire[Index].default.AmmoClass != none) Capacity[Index] = Fire[Index].default.AmmoClass.default.MaxAmmo; } function GetMagazineSize(out int MagazineSize[2]) { MagazineSize[0] = Weapon.default.MagCapacity; MagazineSize[1] = 0; // Can't be obtained normally } function GetFireRate(out float FireRate[2], optional int Index) { FireRate[Index] = 0; if (Index == 0) GetFirerate(FireRate, 1); if (Fire[Index] != none) FireRate[Index] = Fire[Index].default.FireRate; } function GetReloadSpeed(out float ReloadSpeed[2], optional int Index) { ReloadSpeed[Index] = 0; if (Index == 0) GetReloadSpeed(ReloadSpeed, 1); if (Fire[Index] != none) ReloadSpeed[Index] = Weapon.default.ReloadRate; // (3) } function GetSpread(out float Spread[2], optional int Index) { Spread[Index] = 0; if (Index == 0) GetSpread(Spread, 1); if (Fire[Index] != none) Spread[Index] = Fire[Index].default.Spread; } function GetDamage(out int Damage[2], optional int Index) { Damage[Index] = 0; if (Index == 0) GetDamage(Damage, 1); if (Fire[Index] != none) { if (class<InstantFire>(Fire[Index]) != none) // HITSCAN Damage[Index] = class<InstantFire>(Fire[Index]).default.DamageMax; else if(class<BaseProjectileFire>(Fire[Index]) != none) // PROJECTILE { if (class<MP7MMedicGun>(Weapon) != none) Damage[Index] = class<MP7MMedicGun>(Weapon).default.HealBoostAmount; else if (class<M7A3MMedicGun>(Weapon) != none) Damage[Index] = class<M7A3MMedicGun>(Weapon).default.HealBoostAmount; else Damage[Index] = class<BaseProjectileFire>(Fire[Index]).default.ProjectileClass.default.Damage; } else if (class<KFMeleeFire>(Fire[Index]) != none) // MELEE { Damage[Index] = class<KFMeleeFire>(Fire[Index]).default.DamageConst + class<KFMeleeFire>(Fire[Index]).default.MaxAdditionalDamage; } } } function GetDamageRadius(out float DamageRadius[2], optional int Index) { local class<DamageType> DT; DamageRadius[Index] = 0; if (Index == 0) GetDamageRadius(DamageRadius, 1); if (Fire[Index] != none && class<BaseProjectileFire>(Fire[Index]) != none) { DT = class<BaseProjectileFire>(Fire[Index]).default.ProjectileClass.default.MyDamageType; if (class<KFWeaponDamageType>(DT) != none) { if (class<KFWeaponDamageType>(DT).default.bIsExplosive) DamageRadius[Index] = class<BaseProjectileFire>(Fire[Index]).default.ProjectileClass.default.DamageRadius; } } } function GetHeadMultiplier(out float HeadMultiplier[2], optional int Index) { local class<Projectile> P; HeadMultiplier[Index] = 1.0; if (Index == 0) GetHeadMultiplier(HeadMultiplier, 1); if (Fire[Index] != none) { if (class<InstantFire>(Fire[Index]) != none) // HITSCAN { if (class<KFWeaponDamageType>(class<InstantFire>(Fire[Index]).default.DamageType) != none) HeadMultiplier[Index] = class<KFWeaponDamageType>( class<InstantFire>(Fire[Index]).default.DamageType).default.HeadShotDamageMult; } else if (class<BaseProjectileFire>(Fire[Index]) != none) // PROJECTILE { P = class<BaseProjectileFire>(Fire[Index]).default.ProjectileClass; if (class<ShotgunBullet>(P) != none) // MOST PROJECTILES HeadMultiplier[Index] = class<ShotgunBullet>(P).default.HeadShotDamageMult; else if (class<CrossbowArrow>(P) != none) // CROSSBOW HeadMultiplier[Index] = class<CrossbowArrow>(P).default.HeadShotDamageMult; else if (class<HuskGunProjectile>(P) != none) // HUSK GUN HeadMultiplier[Index] = class<HuskGunProjectile>(P).default.HeadShotDamageMult; else if (class<M99Bullet>(P) != none) // M99 HeadMultiplier[Index] = class<M99Bullet>(P).default.HeadShotDamageMult; } else if (class<KFMeleeFire>(Fire[Index]) != none) // MELEE { if (class<DamTypeMelee>(class<KFMeleeFire>(Fire[Index]).default.hitDamageClass) != none) HeadMultiplier[Index] = class<DamTypeMelee>(class<KFMeleeFire>(Fire[Index]).default.hitDamageClass).default.HeadShotDamageMult; } } } function GetPellets(out int Pellets[2], optional int Index) { Pellets[Index] = 0; if (Index == 0) GetPellets(Pellets, 1); if (Fire[Index] != none && class<KFShotgunFire>(Fire[Index]) != none) { if (IgnoresLoad(Fire[Index])) // (1) see note Pellets[Index] = class<BaseProjectileFire>(Fire[Index]).default.ProjPerFire; else Pellets[Index] = class<BaseProjectileFire>(Fire[Index]).default.ProjPerFire * class<BaseProjectileFire>(Fire[Index]).default.AmmoPerFire; } } function GetMaxPens(out int MaxPens[2], optional int Index) { local class<Projectile> P; MaxPens[Index] = 0; if (Index == 0) GetMaxPens(MaxPens, 1); if (class<InstantFire>(Fire[Index]) != none) // HITSCAN { // (2) Deagle, MK23, 44Magnum } else if (class<BaseProjectileFire>(Fire[Index]) != none) // PROJECTILE { P = class<BaseProjectileFire>(Fire[Index]).default.ProjectileClass; if (class<ShotgunBullet>(P) != none) MaxPens[Index] = class<ShotgunBullet>(P).default.MaxPenetrations; } } function GetPenReduction(out float PenReduction[2], optional int Index) { local class<Projectile> P; PenReduction[Index] = 0; if (Index == 0) GetPenReduction(PenReduction, 1); if (class<BaseProjectileFire>(Fire[Index]) != none) { P = class<BaseProjectileFire>(Fire[Index]).default.ProjectileClass; if (class<ShotgunBullet>(P) != none) PenReduction[Index] = class<ShotgunBullet>(P).default.PenDamageReduction; } } defaultproperties { GroupName="KFStatOutputMut" FriendlyName"KFStatOutput" Description="..." }