Prepare fixtures

This commit is contained in:
dkanus 2026-07-14 20:27:09 +07:00
commit 9c94356263
6021 changed files with 722805 additions and 22 deletions

View file

@ -0,0 +1,186 @@
Class Ach extends ScrnAchievements;
#exec OBJ LOAD FILE=ScrnAch_T.utx
protected simulated function int ReadProgressFromData(int AchIndex)
{
if ( AchIndex >= 19 && AchIndex <= 21 ) {
//kill counter
if ( RepLink != none )
return min(RepLink.RKillsStat, AchDefs[AchIndex].MaxProgress);
else
return 0; // RepLink isn't set yet
}
return super.ReadProgressFromData(AchIndex);
}
simulated function Tick(float DeltaTime)
{
if ( Role < ROLE_Authority ) {
if ( GetRepLink() == none )
return; // RepLink isn't set yet
if ( RepLink.RKillsStat <= 0 )
return; // initial replication data is not received yet
ClientSetAchProgress(19, ReadProgressFromData(19), true);
ClientSetAchProgress(20, ReadProgressFromData(20), true);
ClientSetAchProgress(21, ReadProgressFromData(21), true);
}
Disable('Tick');
}
defaultproperties
{
AchDefs(0)=(id="WinCustomMaps",DisplayName="Curious",Description="Survive on %c community-made maps",Icon=Texture'KillingFloorHUD.Achievements.Achievement_5',MaxProgress=10,DataSize=6,Group="Map")
AchDefs(1)=(id="WinCustomMaps1",DisplayName="Wanderer",Description="Survive on %c community-made maps",Icon=Texture'KillingFloorHUD.Achievements.Achievement_11',MaxProgress=25,DataSize=-1,Group="Map")
AchDefs(2)=(id="WinCustomMaps2",DisplayName="Explorer",Description="Survive on %c community-made maps",Icon=Texture'KillingFloorHUD.Achievements.Achievement_17',MaxProgress=50,DataSize=-1,Group="Map")
AchDefs(3)=(id="WinCustomMapsNormal",DisplayName="Piece of Cake",Description="Survive on %c custom maps in ScrN Balance mode",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_109',MaxProgress=7,DataSize=3,Group="Map")
AchDefs(4)=(id="WinCustomMapsHard",DisplayName="Pound Cake",Description="Survive on %c custom maps against Super/Custom specimens",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_110',MaxProgress=5,FilterMaskAll=2,DataSize=3,Group="Map")
AchDefs(5)=(id="WinCustomMapsSui",DisplayName="Cyanide Cake",Description="Survive on %c custom maps against Custom end-game Boss",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_111',MaxProgress=5,FilterMaskAll=4,DataSize=3,Group="Map")
AchDefs(6)=(id="WinCustomMapsHoE",DisplayName="Devil Cake",Description="Survive on %c custom maps against Doom3 monsters",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_112',MaxProgress=3,FilterMaskAll=8,DataSize=3,Group="Map")
AchDefs(7)=(id="KillSuperPat",DisplayName="Death to the Super Scientist",Description="Defeat the Hard or Super Patriarch",Icon=Texture'KillingFloorHUD.Achievements.Achievement_42',MaxProgress=1,FilterMaskAll=68,DataSize=1)
AchDefs(8)=(id="MerryMen",DisplayName="Merry Men",Description="Kill the Patriarch when everyone is ONLY using Crossbows",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_58',MaxProgress=1,bForceShow=True,DataSize=1,Group="TW")
AchDefs(9)=(id="MerryMen50cal",DisplayName="Merry Men .50",Description="Kill the Patriarch when everyone is ONLY using M99",Icon=Texture'ScrnAch_T.Achievements.MerryMen50',MaxProgress=1,bForceShow=True,DataSize=1,Group="TW")
AchDefs(10)=(id="ThinIcePirouette",DisplayName="Thin-Ice Pirouette",Description="Complete %c waves when the rest of your team has died (requires 4+ players)",Icon=Texture'KillingFloorHUD.Achievements.Achievement_36',MaxProgress=10,DataSize=4)
AchDefs(11)=(id="Kenny",DisplayName="OMG, We Have Kenny!",Description="Having one of you dying almost every wave",Icon=Texture'ScrnAch_T.Achievements.Kenny',MaxProgress=1,DataSize=1)
AchDefs(12)=(id="PerkFavorite",DisplayName="Favorite Perk",Description="Survive a game from beginning till the end without changing your perk",Icon=Texture'ScrnAch_T.Achievements.PerkFavorite',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(13)=(id="PerfectBalance",DisplayName="Perfect Balance",Description="Survive 6+ player game having 1 player per perk",Icon=Texture'ScrnAch_T.Achievements.PerfectBalance',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(14)=(id="MrPerky",DisplayName="Mr. Golden Perky",Description="Get All of your Perks up to Level 6",Icon=Texture'KillingFloorHUD.Achievements.Achievement_39',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(15)=(id="PerkGreen",DisplayName="Wow, a Green Icon!",Description="Reach Level 11",Icon=Texture'ScrnAch_T.Achievements.PerkGreen',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(16)=(id="PerkBlue",DisplayName="Blue Gold",Description="Reach Level 16",Icon=Texture'ScrnAch_T.Achievements.PerkBlue',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(17)=(id="PerkPurple",DisplayName="Purple Reign",Description="Reach Level 21",Icon=Texture'ScrnAch_T.Achievements.PerkPurple',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(18)=(id="PerkOrange",DisplayName="Nothing Rhymes with Orange",Description="Reach Level 26",Icon=Texture'ScrnAch_T.Achievements.PerkOrange',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(19)=(id="Kill1000Zeds",DisplayName="Hidden Zero in Experimenticenticide",Description="Kill 1,000 Specimens",Icon=Texture'KillingFloorHUD.Achievements.Achievement_18',MaxProgress=1000,DataSize=-2,Group="Exp")
AchDefs(20)=(id="Kill10000Zeds",DisplayName="Hidden Zero II",Description="Kill 10,000 Specimens",Icon=Texture'KillingFloorHUD.Achievements.Achievement_19',MaxProgress=10000,DataSize=-1,Group="Exp")
AchDefs(21)=(id="Kill100000Zeds",DisplayName="Hidden Zero III",Description="Kill 100,000 Specimens",Icon=Texture'KillingFloorHUD.Achievements.Achievement_20',MaxProgress=100000,DataSize=-1,Group="Exp")
AchDefs(22)=(id="OldSchoolKiting",DisplayName="Old-School Kiting",Description="Kill 15 Fleshpounds with an Axe",Icon=Texture'KillingFloorHUD.Achievements.Achievement_31',MaxProgress=15,DataSize=4,Group="Exp")
AchDefs(23)=(id="SuicideBomber",DisplayName="Suicide Bomber",Description="Detonate grenade in your hands, killing at least 5 zeds with it",Icon=Texture'ScrnAch_T.Achievements.Ahmed',MaxProgress=1,bForceShow=True,DataSize=1)
AchDefs(24)=(id="Snipe250SC",DisplayName="Sharpening Scrakes",Description="Kill %c Scrakes with Sharpshooter's weapons",Icon=Texture'ScrnAch_T.Achievements.ScrakeSniper250',MaxProgress=250,DataSize=8,Group="Exp")
AchDefs(25)=(id="BringingLAW",DisplayName="Bringing the LAW",Description="Kill 100 Big Zeds with L.A.W.",Icon=Texture'KillingFloorHUD.Achievements.Achievement_41',MaxProgress=100,DataSize=8,Group="Exp")
AchDefs(26)=(id="FastShot",DisplayName="Fast Shot",Description="Stun&Kill 100 Husks before they hurt anyone",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_148',MaxProgress=100,DataSize=8,Group="Exp")
AchDefs(27)=(id="NapalmStrike",DisplayName="Napalm Strike",Description="Kill 20 specimens with a single napalm blow",Icon=Texture'KillingFloorHUD.Achievements.Achievement_23',MaxProgress=1,bForceShow=True,DataSize=1,Group="Master")
AchDefs(28)=(id="HC4Kills",DisplayName="One Bloody Handsome",Description="Kill 4 specimens with a single shot of a Handcannon",Icon=Texture'KillingFloorHUD.Achievements.Achievement_29',MaxProgress=1,DataSize=1,Group="Master")
AchDefs(29)=(id="Magnum12Kills",DisplayName="Double Penetration",Description="Kill 12 specimens with Magnum .44 without reloading",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_169',MaxProgress=1,bForceShow=True,DataSize=1,Group="Master")
AchDefs(30)=(id="MK23_12Kills",DisplayName="Penetration is for Pussies",Description="Kills 12 specimens with headshots from MK23 without reloading",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_176',MaxProgress=1,bForceShow=True,DataSize=1,Group="Master")
AchDefs(31)=(id="BruteXbow",DisplayName="Brutal Men",Description="Kill %c Brutes with Crossbow or M99 without taking a damage",Icon=Texture'ScrnAch_T.Achievements.BruteSniper',MaxProgress=30,FilterMaskAll=32,DataSize=5,Group="Master")
AchDefs(32)=(id="BruteM14",DisplayName="Brutal Dot",Description="Kill %c Brutes with M14 without taking a damage",Icon=Texture'ScrnAch_T.Achievements.BruteM14',MaxProgress=50,FilterMaskAll=32,DataSize=6,Group="Master")
AchDefs(33)=(id="BruteScar",DisplayName="Brutally SCAR'd",Description="Kill %c Brutes with SCAR without taking a damage",Icon=Texture'ScrnAch_T.Achievements.BruteScar',MaxProgress=15,FilterMaskAll=32,DataSize=4,Group="Master")
AchDefs(34)=(id="Kill100FPExplosives",DisplayName="Pound This",Description="Kill %c Fleshpounds with explosives",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_64',MaxProgress=100,DataSize=7,Group="Exp")
AchDefs(35)=(id="Nail250Zeds",DisplayName="Nail'd",Description="Nail %c alive zeds to walls",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_186',MaxProgress=250,DataSize=8,Group="Exp")
AchDefs(36)=(id="NailPush100m",DisplayName="Fly High",Description="Push %c zeds at least 100m away with Nailgun",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_61',MaxProgress=10,DataSize=4,Group="Exp")
AchDefs(37)=(id="NailPushShiver",DisplayName="Teleported Back",Description="Push back headless Shiver with Nailgun",Icon=Texture'ScrnAch_T.Achievements.Teleport',MaxProgress=1,FilterMaskAll=32,DataSize=1)
AchDefs(38)=(id="TrueCowboy",DisplayName="True Cowboy",Description="Spend an entire wave in Cowboy Mode",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_170',MaxProgress=1,DataSize=1,Group="Master")
AchDefs(39)=(id="MadCowboy",DisplayName="Mad Cowboy",Description="Kill 8 zeds with Machine Pistols without releasing a trigger",Icon=Texture'ScrnAch_T.Achievements.CrazyCowboy',MaxProgress=1,bForceShow=True,DataSize=1,Group="Master")
AchDefs(40)=(id="M4203Kill50Zeds",DisplayName="#1 In Trash Cleaning",Description="Kill 40 zeds in one wave with M4-203 SE",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_165',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(41)=(id="M99Kill3SC",DisplayName="Ain't Looking For Easy Ways",Description="Kill %c Raged Scrakes with M99 headshots",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_180',MaxProgress=3,DataSize=2)
AchDefs(42)=(id="ExplosionLove",DisplayName="Explosion of Love",Description="Heal 6 players with one medic grenade",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_187',MaxProgress=1,DataSize=1)
AchDefs(43)=(id="iDoT",DisplayName="Power of iDoT",Description="Reach 300dps incremental Damage over Time (iDoT) with flares",Icon=Texture'ScrnAch_T.Achievements.iDoT',MaxProgress=1,DataSize=1)
AchDefs(44)=(id="Unassisted",DisplayName="Unassisted",Description="Solo-kill Fleshpound in 6+ player game",Icon=Texture'ScrnAch_T.Achievements.Unassisted',MaxProgress=1,bForceShow=True,DataSize=1,Group="Master")
AchDefs(45)=(id="TW_SC_LAWHSG",DisplayName="TeamWork: When Size Matters",Description="Finish %c LAW-stunned Scrakes with Hunting or Combat Shotgun",Icon=Texture'ScrnAch_T.Teamwork.SC_LAWHSG',MaxProgress=30,DataSize=5,Group="TW")
AchDefs(46)=(id="TW_SC_Instant",DisplayName="TeamWork: Instant Kill",Description="Kill %c Scrakes with two simultaneous Crossbow/M99 headshots",Icon=Texture'ScrnAch_T.Teamwork.SC_InstantKill',MaxProgress=30,bForceShow=True,DataSize=5,Group="TW")
AchDefs(47)=(id="TW_Siren",DisplayName="TeamWork: No Big Guns on Skinny Bitches",Description="Kill %c Sirens with Pistols + Assault Rifles",Icon=Texture'ScrnAch_T.Teamwork.siren',MaxProgress=100,DataSize=7,Group="TW")
AchDefs(48)=(id="TW_Shiver",DisplayName="TeamWork: Grilled Shiver Brains",Description="Decapitate %c burning Shivers with Assault Rifles",Icon=Texture'ScrnAch_T.Teamwork.Shiver',MaxProgress=250,FilterMaskAll=32,DataSize=8,Group="TW")
AchDefs(49)=(id="TW_Husk_Stun",DisplayName="TeamWork: Stunning Shot, Mate!",Description="Finish %c stunned Husks with Shotguns",Icon=Texture'ScrnAch_T.Teamwork.Husk_Stun',MaxProgress=30,DataSize=6,Group="TW")
AchDefs(50)=(id="TW_FP_Snipe",DisplayName="TeamWork: Sharpened Flesh",Description="Headshot-kill %c Fleshpounds by 2+ Sharpshooters",Icon=Texture'ScrnAch_T.Teamwork.FP_XBOWM14',MaxProgress=15,DataSize=4,Group="TW")
AchDefs(51)=(id="TW_FP_Pipe",DisplayName="TeamWork: Sniper Blow",Description="Rage %c Fleshpounds directly on a pipebomb with Crossbow/M99",Icon=Texture'ScrnAch_T.Teamwork.FP_M99Pipe',MaxProgress=15,DataSize=4,Group="TW")
AchDefs(52)=(id="ScrakeNader",DisplayName="Scrake Nader",Description="Rage %c stunned Scrakes with hand grenades",Icon=Texture'ScrnAch_T.Achievements.ScrakeNaders',MaxProgress=50,DataSize=8)
AchDefs(53)=(id="ScrakeUnnader",DisplayName="Why the Hell Are You Nading Scrakes?!",Description="Kill %c naded Scrakes with sniper weapons, before they do any damage to your retarded teammates.",Icon=Texture'ScrnAch_T.Achievements.ScrakeUnnader',MaxProgress=50,DataSize=8)
AchDefs(54)=(id="TouchOfSavior",DisplayName="Touch of Savior",Description="Make %c heals, saving player from a death",Icon=Texture'ScrnAch_T.Achievements.TouchOfSavior',MaxProgress=15,DataSize=4,Group="Exp")
AchDefs(55)=(id="OnlyHealer",DisplayName="I Heal, You - Shoot!",Description="Be the only healing person in 4+player team for %c waves (200+hp)",Icon=Texture'KillingFloorHUD.Achievements.Achievement_35',MaxProgress=10,DataSize=4,Group="Exp")
AchDefs(56)=(id="CombatMedic",DisplayName="Combat Medic",Description="Heal %c players and kill their enemies too",Icon=Texture'ScrnAch_T.Achievements.CombatMedic',MaxProgress=100,DataSize=8,Group="Exp")
AchDefs(57)=(id="MeleeKillCrawlers",DisplayName="My Kung Fu is Better",Description="Melee-kill %c Crawlers without taking a damage",Icon=Texture'ScrnAch_T.Achievements.MeleeCrawler',MaxProgress=250,DataSize=8,Group="Master")
AchDefs(58)=(id="MeleeHitBehind",DisplayName="My Kung Fu is Stronger",Description="Melee-hit %c zeds from behind",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_120',MaxProgress=250,DataSize=8,Group="Master")
AchDefs(59)=(id="MeleeDecapBloats",DisplayName="My Kung Fu Doesn't Make You Puke",Description="Decapitate %c Bloats with melee weapons without getting puked",Icon=Texture'KillingFloorHUD.Achievements.Achievement_30',MaxProgress=50,DataSize=6,Group="Master")
AchDefs(60)=(id="Ash",DisplayName="Tribute to Ash Williams",Description="Kill 40 zeds in a wave with Boomstick and Chainsaw. Do not use any other weapons!",Icon=Texture'ScrnAch_T.Achievements.Ash',MaxProgress=1,bForceShow=True,DataSize=1)
AchDefs(61)=(id="Overkill",DisplayName="Overkill",Description="Shoot a Crawler in the head with M99",Icon=Texture'ScrnAch_T.Achievements.Overkill',MaxProgress=1,DataSize=1)
AchDefs(62)=(id="BruteExplosive",DisplayName="Block THIS!",Description="Kill %c Brutes with explosive damage",Icon=Texture'ScrnAch_T.Achievements.BruteExplosive',MaxProgress=15,DataSize=4,Group="Exp")
AchDefs(63)=(id="KillHuskHuskGun",DisplayName="Burning Irony",Description="Kill %c Husks with Husk Cannon",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_57',MaxProgress=30,DataSize=5,Group="Exp")
AchDefs(64)=(id="HFC",DisplayName="Horzine Fried Crawler",Description="Recipe: Burn %c Crawlers at temp. below 80C until they die.",Icon=Texture'ScrnAch_T.Achievements.HFC',MaxProgress=999,DataSize=10,Group="Exp")
AchDefs(65)=(id="CarveRoast",DisplayName="Let Me Carve a Roast",Description="Kill %c crispified zeds with melee weapons.",Icon=Texture'ScrnAch_T.Achievements.CarveRoast',MaxProgress=30,DataSize=6)
AchDefs(66)=(id="DotOfDoom",DisplayName="Dot of Doom",Description="Get 25 headshots in a row with the M14EBR.",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_60',MaxProgress=1,bForceShow=True,DataSize=1,Group="Master")
AchDefs(67)=(id="Money10k",DisplayName="I Need DOSH!",Description="Start a wave having 10,000 pounds of cash",Icon=Texture'KillingFloorHUD.Achievements.Achievement_37',MaxProgress=1,DataSize=1)
AchDefs(68)=(id="Welcome",DisplayName="Welcome to ScrN Balance!",Description="Welcome to the ScrN Total Game Balance Community! Enjoy the best modification for Killing Floor.",Icon=Texture'ScrnAch_T.Achievements.PerfectBalance',MaxProgress=1,DataSize=1)
AchDefs(69)=(id="MedicOfDoom",DisplayName="Medic of Doom",Description="Kill 15 zeds with M4-203M Medic Rifle without reloading.",Icon=Texture'ScrnAch_T.Master.MedicOfDoom',MaxProgress=1,DataSize=1,Group="Master")
AchDefs(70)=(id="Plus25Clots",DisplayName="+25 Clot kills",Description="Kill 25 clots having less than 4 seconds between subsequent kills.",Icon=Texture'ScrnAch_T.Master.Plus25Clots',MaxProgress=1,DataSize=1,Group="Master")
AchDefs(71)=(id="GetOffMyLawn",DisplayName="I said get off my Lawn!",Description="Kill %c Fleshpounds with the Boomstick or Combat Shotgun.",Icon=Texture'ScrnAch_T.Master.GetOffMyLawn',MaxProgress=15,DataSize=4,Group="Exp")
AchDefs(72)=(id="Accuracy",DisplayName="Accuracy",Description="Finish %c waves with 75% headshot accuracy. At least 30 decapitations required per wave.",Icon=Texture'ScrnAch_T.Master.Accuracy',MaxProgress=10,DataSize=4,Group="Master")
AchDefs(73)=(id="SteampunkSniper",DisplayName="Steampunk Sniper",Description="Score 10 headshots in a row with Musket. Do it %c times.",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_224',MaxProgress=4,DataSize=3,Group="Master")
AchDefs(74)=(id="MeleeGod",DisplayName="Melee God",Description="Kill %c Scrakes with only head-hits from melee weapons. Buzzsaw Bow excluding.",Icon=Texture'ScrnAch_T.Master.Gauntlet',MaxProgress=30,DataSize=5,Group="Master")
AchDefs(75)=(id="HuskGunSC",DisplayName="Weird but usefull",Description="Kill %c Scrakes with the Husk Gun.",Icon=Texture'ScrnAch_T.Exp.HuskGunSC',MaxProgress=30,DataSize=5,Group="Exp")
AchDefs(76)=(id="Impressive",DisplayName="Impressive",Description="Score 5 headshots in a row %c times.",Icon=Texture'ScrnAch_T.Exp.Impressive',MaxProgress=250,DataSize=8,Group="Exp")
AchDefs(77)=(id="GrimReaper",DisplayName="Grim Reaper",Description="Kill %c zeds with Scythe.",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_193',MaxProgress=250,DataSize=8,Group="Exp")
AchDefs(78)=(id="MindBlowingSacrifice",DisplayName="Mind-Blowing Sacrifice",Description="Kill %c Fleshpounds by blocking them on own pipes.",Icon=Texture'ScrnAch_T.Achievements.MindBlowingSacrifice',MaxProgress=7,DataSize=3,Group="Exp")
AchDefs(79)=(id="PrematureDetonation",DisplayName="Premature Detonation",Description="Kill %c zeds with undetonated grenades or rockets.",Icon=Texture'ScrnAch_T.Achievements.PrematureDetonation',MaxProgress=15,DataSize=4,Group="Exp")
AchDefs(80)=(id="NoHeadshots",DisplayName="Hitboxes Are Overrated",Description="Kill %c big zeds without landing any headshot and taking damage.",Icon=Texture'ScrnAch_T.Exp.NoHeadshots',MaxProgress=62,DataSize=6,Group="Exp")
AchDefs(81)=(id="BitterIrony",DisplayName="Bitter Irony",Description="Kill %c Scrakes with a Chainsaw.",Icon=Texture'KillingFloorHUD.Achievements.Achievement_25',MaxProgress=62,DataSize=6,Group="Exp")
AchDefs(82)=(id="BallsOfSteel",DisplayName="Balls of Steel",Description="Survive an entire game without wearing heavy armor, damage resistance and dying.",Icon=Texture'ScrnAch_T.Exp.BallsOfSteel',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(83)=(id="OutOfTheGum",DisplayName="Out of the Gum",Description="Kill 30 specimens with bullets, having less than 5 seconds betwen subsequent kills.",Icon=Texture'ScrnAch_T.Exp.OutOfTheGum',MaxProgress=1,DataSize=1,Group="Exp")
AchDefs(84)=(id="HorzineArmor",DisplayName="Good Defence Is NOT a Good Offence",Description="Survive %c times after taking a heavy damage, thanks to wearing a Horzine Armor.",Icon=Texture'ScrnAch_T.Exp.HorzineArmor',MaxProgress=7,DataSize=3,Group="Exp")
AchDefs(85)=(id="RocketBlow",DisplayName="I Love Rocket Blow",Description="Kill 10 specimens with a single rocket blow. Liked it? Then do it %c times.",Icon=Texture'ScrnAch_T.Exp.RocketBlow',MaxProgress=30,DataSize=5,Group="Exp")
AchDefs(86)=(id="SavingResources",DisplayName="Saving Resources",Description="Save %c pipebombs from Bloats or Sirens.",Icon=Texture'ScrnAch_T.Exp.SavingResources',MaxProgress=15,DataSize=4,Group="Exp")
AchDefs(87)=(id="Gunslingophobia",DisplayName="Gunslingophobia",Description="One-shot kill %c Crawlers with pistols.",Icon=Texture'ScrnAch_T.Exp.Gunslingophobia',MaxProgress=1001,DataSize=10,Group="Exp")
AchDefs(88)=(id="OldGangster",DisplayName="Old Gangster",Description="Kill 5 zeds without releasing a trigger of your Tommy Gun (drum mag.)",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_227',MaxProgress=55,DataSize=6,Group="Exp")
AchDefs(89)=(id="TW_PipeBlock",DisplayName="TeamWork: Hold On, The Big One! Take a Present.",Description="Block %c big zeds on pipebombs without taking significant damage.",Icon=Texture'ScrnAch_T.Teamwork.PipeBlock',MaxProgress=30,DataSize=5,Group="TW")
AchDefs(90)=(id="TW_BackstabSC",DisplayName="TeamWork: Taking From Behind",Description="Attract %c Scrakes on yourself, allowing teammate to backstab him.",Icon=Texture'ScrnAch_T.Teamwork.BackstabScrakes',MaxProgress=30,DataSize=5,Group="TW")
AchDefs(91)=(id="NoI",DisplayName="There is no I in the TEAM",Description="Finish the wave, where all (3+) players have almost the same kill count (+/-10%).",Icon=Texture'ScrnAch_T.Teamwork.NoI',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(92)=(id="PatMelee",DisplayName="We Don't Give a **** About The Radial Attack",Description="Kill Patriarch with melee weapons only.",Icon=Texture'ScrnAch_T.Teamwork.PatMelee',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(93)=(id="Pat9mm",DisplayName="Peashooters",Description="Kill End Game Boss with 9mm pistols only.",Icon=Texture'ScrnAch_T.Teamwork.Peashooters',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(94)=(id="PatPrey",DisplayName="Hunting the Prey",Description="Hunt the Patriarch during his heal-runs and kill him in 2:00 without focusing on other specimens.",Icon=Texture'ScrnAch_T.Teamwork.PatPrey',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(95)=(id="PerfectWave",DisplayName="Perfect Wave",Description="Survive %c waves without anybody taking a damage. Wave 1 excluding.",Icon=Texture'ScrnAch_T.Teamwork.PerfectWave',MaxProgress=15,DataSize=4,Group="TW")
AchDefs(96)=(id="PerfectGame",DisplayName="Perfect Game",Description="Survive 2+ player game without a single player death.",Icon=Texture'ScrnAch_T.Teamwork.PerfectGame',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(97)=(id="SpeedrunBronze",DisplayName="Speedrun Bronze",Description="Win a long game in 45 minutes. Map should have at least 3 traders.",Icon=Texture'ScrnAch_T.Teamwork.SpeedrunBronze',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(98)=(id="SpeedrunSilver",DisplayName="Speedrun Silver",Description="Win a long game in 40 minutes. Map should have at least 3 traders.",Icon=Texture'ScrnAch_T.Teamwork.SpeedrunSilver',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(99)=(id="SpeedrunGold",DisplayName="Speedrun Gold",Description="Win a long game in 33 minutes. Map should have at least 3 traders.",Icon=Texture'ScrnAch_T.Teamwork.SpeedrunGold',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(100)=(id="Blame55p",DisplayName="Acute Case of Fecalphilia",Description="Blame 55 things. Make a good reason for doing that.",Icon=Texture'ScrnAch_T.Achievements.Blame55p',MaxProgress=55,DataSize=6)
AchDefs(101)=(id="BlameMe",DisplayName="Self-Criticism Approved",Description="Blame yourself. Make a good reason for doing that.",Icon=Texture'ScrnAch_T.Achievements.BlameMe',MaxProgress=1,DataSize=1)
AchDefs(102)=(id="BlameTeam",DisplayName="You Guys Suck",Description="Blame your team. Make a good reason for doing that.",Icon=Texture'ScrnAch_T.Achievements.BlameTeam',MaxProgress=1,DataSize=1)
AchDefs(103)=(id="MaxBlame",DisplayName="Conductor of the Poop Train",Description="Get blamed 5 times in one game.",Icon=Texture'ScrnAch_T.Achievements.PoopTrain',MaxProgress=1,bForceShow=True,DataSize=1)
AchDefs(104)=(id="KillWhore",DisplayName="KillWhore",Description="Get 2.5x more kills than any other player in your team (5+p).",Icon=Texture'ScrnAch_T.Achievements.KillWhore',MaxProgress=1,bForceShow=True,DataSize=1)
AchDefs(105)=(id="ComeatMe",DisplayName="Come at Me, Bro!",Description="Kill a Jason with a Machete.",Icon=Texture'ScrnAch_T.Achievements.ComeatMe',MaxProgress=1,FilterMaskAll=32,DataSize=1)
AchDefs(106)=(id="Friday13",DisplayName="Friday the 13th",Description="Survive the wave after 3 of your teammates got killed by Jason Voorhees.",Icon=Texture'ScrnAch_T.Achievements.Friday13',MaxProgress=1,FilterMaskAll=32,DataSize=1)
AchDefs(107)=(id="ClotHater",DisplayName="Clot Hater",Description="Kill 15 Clots in a row. Do it %c times. Cuz you really hate them.",Icon=Texture'ScrnAch_T.Achievements.ClotHater',MaxProgress=15,DataSize=4)
AchDefs(108)=(id="MadeinChina",DisplayName="Made in China",Description="Get blown up by your own Pipebomb.",Icon=Texture'ScrnAch_T.Achievements.MadeinChina',MaxProgress=1,DataSize=1)
AchDefs(109)=(id="FastVengeance",DisplayName="Fast Vengeance",Description="Kill a zed within 5 seconds of it killed a teammate.",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_198',MaxProgress=1,DataSize=1)
AchDefs(110)=(id="Overkill1",DisplayName="Overkill vol.1",Description="Kill a Crawler with a headshot from fully-charged Husk Gun.",Icon=Texture'ScrnAch_T.Achievements.Overkill1',MaxProgress=1,DataSize=1)
AchDefs(111)=(id="Overkill2",DisplayName="Overkill vol.2",Description="Kill a Crawler with a headshot from undetonated rocket.",Icon=Texture'ScrnAch_T.Achievements.Overkill2',MaxProgress=1,DataSize=1)
AchDefs(112)=(id="Overkill3",DisplayName="Overkill vol.3",Description="Blow up your own pipe, which kills only a single Crawler.",Icon=Texture'ScrnAch_T.Achievements.Overkill3',MaxProgress=1,DataSize=1)
AchDefs(113)=(id="LuxuryFuneral",DisplayName="Savings For a Luxury Funeral",Description="Your teammate was greedy. He had a lot of money to share but he'd choosen to save... for the own funeral.",Icon=Texture'KillingFloorHUD.Achievements.Achievement_27',MaxProgress=1,DataSize=1)
AchDefs(114)=(id="Cookies",DisplayName="All Your Cookies Belong To Me",Description="Kill %c zeds with weapons picked up from dead player corpses.",Icon=Texture'ScrnAch_T.Achievements.Cookies',MaxProgress=13,DataSize=4)
AchDefs(115)=(id="EyeForAnEye",DisplayName="Eye for an Eye",Description="Kill a specimen, who killed your teamate, with a weapon, picked up from his body.",Icon=Texture'ScrnAch_T.Achievements.EyeForAnEye',MaxProgress=1,DataSize=1)
AchDefs(116)=(id="MilkingCow",DisplayName="Milking Cow",Description="Spare $2000 cash with your teammates without receiving it back.",Icon=Texture'ScrnAch_T.Achievements.Cow',MaxProgress=1,DataSize=1)
AchDefs(117)=(id="SpareChange",DisplayName="Spare Change for Homeless",Description="Spare $1 with your poor teammate, who has at least 10x less money than you (including donations).",Icon=Texture'ScrnAch_T.Achievements.SpareChange',MaxProgress=1,DataSize=1)
AchDefs(118)=(id="SellCrap",DisplayName="Want Dosh? Sell THIS!",Description="Blame a player who is begging for money.",Icon=Texture'ScrnAch_T.Achievements.SellCrap',MaxProgress=1,bForceShow=True,DataSize=1)
AchDefs(119)=(id="GhostSmell",DisplayName="I Can Smell Ghosts",Description="Decapitate %c Ghosts with Sharpshooter's weapons from 20+ meters",Icon=Texture'ScrnAch_T.ScrnZeds.GhostSmell',MaxProgress=15,FilterMaskAll=16,DataSize=4,Group="Exp")
AchDefs(120)=(id="Ghostbuster",DisplayName="Ghostbuster",Description="As Commando, kill %c Stalkers or Ghosts within detection range without taking a damage.",Icon=Texture'ScrnAch_T.ScrnZeds.Ghostbuster',MaxProgress=100,FilterMaskAll=16,DataSize=7,Group="Exp")
AchDefs(121)=(id="TeslaBomber",DisplayName="Tesla Bomber",Description="Kill %c ZEDs with Tesla Husks's self-destruct explosion.",Icon=Texture'ScrnAch_T.ScrnZeds.TeslaBomber',MaxProgress=30,FilterMaskAll=16,DataSize=5,Group="Master")
AchDefs(122)=(id="NikolaTesla",DisplayName="Nikola Tesla and You",Description="Kill %c Tesla Husks with close-combat weapons (melee or shotguns). But take some electrical damage before!",Icon=Texture'ScrnAch_T.ScrnZeds.NikolaTesla',MaxProgress=15,FilterMaskAll=16,DataSize=4)
AchDefs(123)=(id="TeslaChain",DisplayName="Chain Reaction",Description="Get connected to 2 other players with Tesla Beams",Icon=Texture'ScrnAch_T.ScrnZeds.TeslaChain',MaxProgress=1,FilterMaskAll=16,DataSize=1)
AchDefs(124)=(id="TSCT",DisplayName="TSC Tournament Member",Description="Participate in TSC Tournement and get into the Playoffs",Icon=Texture'ScrnTex.Tourney.TourneyMember64',MaxProgress=1,DataSize=1,Group="Hidden")
AchDefs(125)=(id="KFG1",DisplayName="'Consider this a warning'",Description="Kill a Husk with Crossbow in 2 seconds after killing another zed with Handcannon",Icon=Texture'ScrnAch_T.Achievements.Stupid',MaxProgress=1,DataSize=1)
AchDefs(126)=(id="KFG2",DisplayName="'Aimbot detected'",Description="Survive Wave 10 with at least 10% headshot accuracy",Icon=Texture'ScrnAch_T.Achievements.Stupid',MaxProgress=1,DataSize=1)
AchDefs(127)=(id="AchReset",DisplayName="Achievement Reset",Description="Reset your achievements (all but maps) by executing 'AchReset' console command.",Icon=Texture'ScrnAch_T.Achievements.AchReset',MaxProgress=1,bForceShow=True,DataSize=1)
AchDefs(128)=(id="MeleeKillMidairCrawlers",DisplayName="My Kung Fu is Awesome",Description="Melee-hit %c Crawlers in midair without taking damage",Icon=Texture'ScrnAch_T.Achievements.MeleeCrawler',MaxProgress=50,DataSize=6,Group="Master")
AchDefs(129)=(id="GunslingerSC",DisplayName="Two Bloody Handsome",Description="Kill %c Scrakes with Dual HC/.44 without taking damage",Icon=Texture'ScrnAch_T.Master.GunslingerSC',MaxProgress=50,DataSize=6,Group="Master")
AchDefs(130)=(id="ProNailer",DisplayName="Pro-Nailer",Description="Decapitate zed with nail ricochet",Icon=Texture'ScrnAch_T.Master.ProNailer',MaxProgress=1,DataSize=1,Group="Master")
AchDefs(131)=(id="TW_NoHeadshots",DisplayName="Hitboxes Are TOTALLY Overrated",Description="Survive 2+player game without scoring any headshots",Icon=Texture'ScrnAch_T.Teamwork.NoobAlert',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(132)=(id="TW_SkullCrackers",DisplayName="SkullCrackers",Description="Survive 2+player game by only using weapons that are capable of doing headshots (no nades, fire etc.)",Icon=Texture'ScrnAch_T.Teamwork.SkullCrackers',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(133)=(id="OP_Medic",DisplayName="Is Medic OP?",Description="Survive 3+player game where everybody is playing Medic",Icon=Texture'ScrnAch_T.Teamwork.OP_Medic',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(134)=(id="OP_Support",DisplayName="Is Support OP?",Description="Survive 3+player game where everybody is playing Support",Icon=Texture'ScrnAch_T.Teamwork.OP_Support',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(135)=(id="OP_Sharpshooter",DisplayName="Is Sharpshooter OP?",Description="Survive 3+player game where everybody is playing Sharpshooter",Icon=Texture'ScrnAch_T.Teamwork.OP_Sharpshooter',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(136)=(id="OP_Commando",DisplayName="Is Commando OP?",Description="Survive 3+player game where everybody is playing Commando",Icon=Texture'ScrnAch_T.Teamwork.OP_Commando',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(137)=(id="OP_Berserker",DisplayName="Is Berserker OP?",Description="Survive 3+player game where everybody is playing Berserker",Icon=Texture'ScrnAch_T.Teamwork.OP_Berserker',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(138)=(id="OP_Firebug",DisplayName="Is Firebug OP?",Description="Survive 3+player game where everybody is playing Firebug",Icon=Texture'ScrnAch_T.Teamwork.OP_Firebug',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(139)=(id="OP_Demo",DisplayName="Is Demo OP?",Description="Survive 3+player game where everybody is playing Demolition",Icon=Texture'ScrnAch_T.Teamwork.OP_Demo',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(140)=(id="OP_Gunslinger",DisplayName="Is Gunslinger OP?",Description="Survive 3+player game where everybody is playing Gunslinger",Icon=Texture'ScrnAch_T.Teamwork.OP_Gunslinger',MaxProgress=1,DataSize=1,Group="TW")
AchDefs(141)=(id="MacheteKillMidairCrawler",DisplayName="Machete Master",Description="Use Machete to melee-kill Crawler in midair without taking damage",Icon=Texture'ScrnAch_T.Master.MacheteCrawlerCut',MaxProgress=1,DataSize=1,Group="Master")
AchDefs(142)=(id="MacheteStunSC",DisplayName="Machete Stuns!",Description="Stun Scrake with Machete",Icon=Texture'ScrnAch_T.Master.MacheteScrake',MaxProgress=1,DataSize=1,Group="Hidden")
AchDefs(143)=(id="MacheteWalker",DisplayName="Machete Marathon",Description="Perform 'Machete-sprint': drop/pickup Machete 422 times while running in a single game",Icon=Texture'ScrnAch_T.Achievements.MacheteWalker',MaxProgress=1,bForceShow=True,DataSize=1,Group="Hidden")
DefaultAchGroup="Misc"
GroupInfo(1)=(Group="Map",Caption="Maps")
GroupInfo(2)=(Group="Exp",Caption="Basic Experience")
GroupInfo(3)=(Group="Master",Caption="Master Skills")
GroupInfo(4)=(Group="TW",Caption="Teamwork")
GroupInfo(5)=(Group="Misc",Caption="Miscellaneous")
ProgressName="Achievements"
}

View file

@ -0,0 +1,225 @@
// shorted class name - less bytes needs to send as custom stat
Class AchMaps extends ScrnMapAchievements;
#exec OBJ LOAD FILE=ScrnAch_T.utx
defaultproperties
{
AchDefs(0)=(id="KF-WestLondon",DisplayName="Pub Crawl",Description="West London",Icon=Texture'KillingFloorHUD.Achievements.Achievement_0')
AchDefs(1)=(id="KF-WestLondonHard",DisplayName="Hard Pub Crawl",Description="West London",Icon=Texture'KillingFloorHUD.Achievements.Achievement_6')
AchDefs(2)=(id="KF-WestLondonSui",DisplayName="Suicidal Pub Crawl",Description="West London",Icon=Texture'KillingFloorHUD.Achievements.Achievement_12')
AchDefs(3)=(id="KF-WestLondonHoe",DisplayName="Hellish Pub Crawl",Description="West London",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_65')
AchDefs(4)=(id="KF-Manor",DisplayName="Lord of the Manor",Description="Manor",Icon=Texture'KillingFloorHUD.Achievements.Achievement_1')
AchDefs(5)=(id="KF-ManorHard",DisplayName="Duke of the Manor",Description="Manor",Icon=Texture'KillingFloorHUD.Achievements.Achievement_7')
AchDefs(6)=(id="KF-ManorSui",DisplayName="Emperor of the Manor",Description="Manor",Icon=Texture'KillingFloorHUD.Achievements.Achievement_13')
AchDefs(7)=(id="KF-ManorHoe",DisplayName="Demonic King of the Manor",Description="Manor",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_66')
AchDefs(8)=(id="KF-Farm",DisplayName="Chicken Farmer",Description="Farm",Icon=Texture'KillingFloorHUD.Achievements.Achievement_2')
AchDefs(9)=(id="KF-FarmHard",DisplayName="Cattle Farmer",Description="Farm",Icon=Texture'KillingFloorHUD.Achievements.Achievement_8')
AchDefs(10)=(id="KF-FarmSui",DisplayName="Alligator Farmer",Description="Farm",Icon=Texture'KillingFloorHUD.Achievements.Achievement_14')
AchDefs(11)=(id="KF-FarmHoe",DisplayName="Demon Farmer",Description="Farm",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_67')
AchDefs(12)=(id="KF-Offices",DisplayName="The Boss",Description="Offices",Icon=Texture'KillingFloorHUD.Achievements.Achievement_3')
AchDefs(13)=(id="KF-OfficesHard",DisplayName="Hard Boss",Description="Offices",Icon=Texture'KillingFloorHUD.Achievements.Achievement_9')
AchDefs(14)=(id="KF-OfficesSui",DisplayName="Mad Boss",Description="Offices",Icon=Texture'KillingFloorHUD.Achievements.Achievement_15')
AchDefs(15)=(id="KF-OfficesHoe",DisplayName="Boss from Hell",Description="Offices",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_68')
AchDefs(16)=(id="KF-BioticsLab",DisplayName="Lab Cleaner",Description="Biotics Lab",Icon=Texture'KillingFloorHUD.Achievements.Achievement_4')
AchDefs(17)=(id="KF-BioticsLabHard",DisplayName="Lab Assistant",Description="Biotics Lab",Icon=Texture'KillingFloorHUD.Achievements.Achievement_10')
AchDefs(18)=(id="KF-BioticsLabSui",DisplayName="Lab Professor",Description="Biotics Lab",Icon=Texture'KillingFloorHUD.Achievements.Achievement_16')
AchDefs(19)=(id="KF-BioticsLabHoe",DisplayName="Scientist from Hell",Description="Biotics Lab",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_69')
AchDefs(20)=(id="KF-Foundry",DisplayName="Tin Man",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_44')
AchDefs(21)=(id="KF-FoundryHard",DisplayName="Steel Worker",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_45')
AchDefs(22)=(id="KF-FoundrySui",DisplayName="Man of Steel",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_46')
AchDefs(23)=(id="KF-FoundryHoe",DisplayName="Diablo Steel Man",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_70')
AchDefs(24)=(id="KF-Bedlam",DisplayName="A Bit Barmy",Description="Bedlam",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_47')
AchDefs(25)=(id="KF-BedlamHard",DisplayName="Gone Mental",Description="Bedlam",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_48')
AchDefs(26)=(id="KF-BedlamSui",DisplayName="Complete Barking",Description="Bedlam",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_49')
AchDefs(27)=(id="KF-BedlamHoe",DisplayName="Commit-ed for life",Description="Bedlam",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_71')
AchDefs(28)=(id="KF-Wyre",DisplayName="Squirrel King of the Dark Forest",Description="Wyre",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_50')
AchDefs(29)=(id="KF-WyreHard",DisplayName="Raccoon King of the Dark Forest",Description="Wyre",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_51')
AchDefs(30)=(id="KF-WyreSui",DisplayName="Bear King of the Dark Forest",Description="Wyre",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_52')
AchDefs(31)=(id="KF-WyreHoe",DisplayName="Wolf King of the Dark Forest",Description="Wyre",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_72')
AchDefs(32)=(id="KF-Biohazard",DisplayName="Waste Disposal",Description="Biohazard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_73')
AchDefs(33)=(id="KF-BiohazardHard",DisplayName="Waste Land",Description="Biohazard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_74')
AchDefs(34)=(id="KF-BiohazardSui",DisplayName="Waste of Space",Description="Biohazard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_75')
AchDefs(35)=(id="KF-BiohazardHoe",DisplayName="Wasted",Description="Biohazard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_76')
AchDefs(36)=(id="KF-Crash",DisplayName="Warehouse Janitor",Description="Crash",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_77')
AchDefs(37)=(id="KF-CrashHard",DisplayName="Warehouse Forklift Operator",Description="Crash",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_78')
AchDefs(38)=(id="KF-CrashSui",DisplayName="Warehouse Foreman",Description="Crash",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_79')
AchDefs(39)=(id="KF-CrashHoe",DisplayName="Warehouse Manager",Description="Crash",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_80')
AchDefs(40)=(id="KF-Departed",DisplayName="Departure Gallery",Description="Departed",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_81')
AchDefs(41)=(id="KF-DepartedHard",DisplayName="Departure Lounge",Description="Departed",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_82')
AchDefs(42)=(id="KF-DepartedSui",DisplayName="Departure Gate",Description="Departed",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_83')
AchDefs(43)=(id="KF-DepartedHoe",DisplayName="Dear Departed",Description="Departed",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_84')
AchDefs(44)=(id="KF-FilthsCross",DisplayName="Running Late",Description="Filths Cross",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_85')
AchDefs(45)=(id="KF-FilthsCrossHard",DisplayName="Missed Connection",Description="Filths Cross",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_86')
AchDefs(46)=(id="KF-FilthsCrossSui",DisplayName="Train Wreck",Description="Filths Cross",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_87')
AchDefs(47)=(id="KF-FilthsCrossHoe",DisplayName="Pile Up",Description="Filths Cross",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_88')
AchDefs(48)=(id="KF-HospitalHorrors",DisplayName="Gimme a Plaster!",Description="Hospital Horrors",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_89')
AchDefs(49)=(id="KF-HospitalHorrorsHard",DisplayName="That Bloody Well Hurts!",Description="Hospital Horrors",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_90')
AchDefs(50)=(id="KF-HospitalHorrorsSui",DisplayName="I'm Dying Here!",Description="Hospital Horrors",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_91')
AchDefs(51)=(id="KF-HospitalHorrorsHoe",DisplayName="Not Dead Yet!",Description="Hospital Horrors",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_92')
AchDefs(52)=(id="KF-Icebreaker",DisplayName="Ice Cube",Description="Icebreaker",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_93')
AchDefs(53)=(id="KF-IcebreakerHard",DisplayName="Crushed Ice",Description="Icebreaker",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_94')
AchDefs(54)=(id="KF-IcebreakerSui",DisplayName="Iceberg",Description="Icebreaker",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_95')
AchDefs(55)=(id="KF-IcebreakerHoe",DisplayName="Comet",Description="Icebreaker",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_96')
AchDefs(56)=(id="KF-MountainPass",DisplayName="Daytrip",Description="Mountain Pass",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_97')
AchDefs(57)=(id="KF-MountainPassHard",DisplayName="Gone Camping",Description="Mountain Pass",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_98')
AchDefs(58)=(id="KF-MountainPassSui",DisplayName="Mountaineer",Description="Mountain Pass",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_99')
AchDefs(59)=(id="KF-MountainPassHoe",DisplayName="Park Ranger",Description="Mountain Pass",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_100')
AchDefs(60)=(id="KF-Suburbia",DisplayName="Park Ranger",Description="Suburbia",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_101')
AchDefs(61)=(id="KF-SuburbiaHard",DisplayName="Private Security",Description="Suburbia",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_102')
AchDefs(62)=(id="KF-SuburbiaSui",DisplayName="Vigilante",Description="Suburbia",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_103')
AchDefs(63)=(id="KF-SuburbiaHoe",DisplayName="SWAT",Description="Suburbia",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_104')
AchDefs(64)=(id="KF-Waterworks",DisplayName="Slight Drip",Description="Waterworks",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_105')
AchDefs(65)=(id="KF-WaterworksHard",DisplayName="Burst Pipe",Description="Waterworks",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_106')
AchDefs(66)=(id="KF-WaterworksSui",DisplayName="Pressure Failure",Description="Waterworks",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_107')
AchDefs(67)=(id="KF-WaterworksHoe",DisplayName="Floodgate to Hell",Description="Waterworks",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_108')
AchDefs(68)=(id="KF-EvilSantasLair",DisplayName="Walking in A Winter Horror Land",Description="EvilSantasLair",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_114')
AchDefs(69)=(id="KF-EvilSantasLairHard",DisplayName="Silent Night, Evil Night",Description="EvilSantasLair",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_115')
AchDefs(70)=(id="KF-EvilSantasLairSui",DisplayName="I'm Dreaming of a Red Christmas",Description="EvilSantasLair",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_116')
AchDefs(71)=(id="KF-EvilSantasLairHoe",DisplayName="Grandma got Eaten by a Reindeer",Description="EvilSantasLair",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_117')
AchDefs(72)=(id="KF-Aperture",DisplayName="Science Got Done",Description="Aperture",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_133')
AchDefs(73)=(id="KF-ApertureHard",DisplayName="Still Alive",Description="Aperture",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_134')
AchDefs(74)=(id="KF-ApertureSui",DisplayName="This is a Triumph",Description="Aperture",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_135')
AchDefs(75)=(id="KF-ApertureHoe",DisplayName="I'm Making a Note Here, Huge Success",Description="Aperture",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_136')
AchDefs(76)=(id="KF-AbusementPark",DisplayName="Flea Circus",Description="Abusement Park",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_138')
AchDefs(77)=(id="KF-AbusementParkHard",DisplayName="Dog and Pony Show",Description="Abusement Park",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_139')
AchDefs(78)=(id="KF-AbusementParkSui",DisplayName="3 Ring Circus",Description="Abusement Park",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_140')
AchDefs(79)=(id="KF-AbusementParkHoe",DisplayName="On Top of the Big Top",Description="Abusement Park",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_141')
AchDefs(80)=(id="KF-IceCave",DisplayName="Snow Cone",Description="Ice Cave",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_171')
AchDefs(81)=(id="KF-IceCaveHard",DisplayName="Stay Frosty",Description="Ice Cave",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_172')
AchDefs(82)=(id="KF-IceCaveSui",DisplayName="On the Rocks",Description="Ice Cave",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_173')
AchDefs(83)=(id="KF-IceCaveHoe",DisplayName="Anti Freeze",Description="Ice Cave",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_174')
AchDefs(84)=(id="KF-Hellride",DisplayName="Highway to Heaven",Description="Hellride",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_181')
AchDefs(85)=(id="KF-HellrideHard",DisplayName="Stuck in Limbo",Description="Hellride",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_182')
AchDefs(86)=(id="KF-HellrideSui",DisplayName="Demonic Road",Description="Hellride",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_183')
AchDefs(87)=(id="KF-HellrideHoe",DisplayName="Devil's Co-pilot",Description="Hellride",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_184')
AchDefs(88)=(id="KF-HillbillyHorror",DisplayName="Third Cousins",Description="Hillbilly Horror",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_97')
AchDefs(89)=(id="KF-HillbillyHorrorHard",DisplayName="Second Cousins",Description="Hillbilly Horror",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_98')
AchDefs(90)=(id="KF-HillbillyHorrorSui",DisplayName="First Cousins",Description="Hillbilly Horror",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_99')
AchDefs(91)=(id="KF-HillbillyHorrorHoe",DisplayName="Zeroth Cousins",Description="Hillbilly Horror",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_100')
AchDefs(92)=(id="KF-MoonBase",DisplayName="Here is to us",Description="Moon Base",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_204')
AchDefs(93)=(id="KF-MoonBaseHard",DisplayName="Attempting Re-entry",Description="Moon Base",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_205')
AchDefs(94)=(id="KF-MoonBaseSui",DisplayName="Amusing Death",Description="Moon Base",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_206')
AchDefs(95)=(id="KF-MoonBaseHoe",DisplayName="One Giant Leap (Back) for Mankind",Description="Moon Base",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_207')
AchDefs(96)=(id="KF-Aventine",DisplayName="Lord of Aventive",Description="Aventine",Icon=Texture'ScrnAch_T.Maps.Aventine_0')
AchDefs(97)=(id="KF-AventineHard",DisplayName="Duke of Aventine",Description="Aventine",Icon=Texture'ScrnAch_T.Maps.Aventine_1')
AchDefs(98)=(id="KF-AventineSui",DisplayName="Emperor of Aventine",Description="Aventine",Icon=Texture'ScrnAch_T.Maps.Aventine_2')
AchDefs(99)=(id="KF-AventineHoE",DisplayName="Demonic King of Aventine",Description="Aventine",Icon=Texture'ScrnAch_T.Maps.Aventine_3')
AchDefs(100)=(id="KF-Constriction",DisplayName="Rats in the Wall",Description="Constriction",Icon=Texture'ScrnAch_T.Maps.Constriction_0')
AchDefs(101)=(id="KF-ConstrictionHard",DisplayName="Barking Dogs Outside",Description="Constriction",Icon=Texture'ScrnAch_T.Maps.Constriction_1')
AchDefs(102)=(id="KF-ConstrictionSui",DisplayName="Screaming Maidens",Description="Constriction",Icon=Texture'ScrnAch_T.Maps.Constriction_2')
AchDefs(103)=(id="KF-ConstrictionHoE",DisplayName="...and the Crazed Lord of the Manor died - again",Description="Constriction",Icon=Texture'ScrnAch_T.Maps.Constriction_3')
AchDefs(104)=(id="KF-CornerMarket_v3",DisplayName="Barrow Boy",Description="Corner Market",Icon=Texture'ScrnAch_T.Maps.CornerMarket_0')
AchDefs(105)=(id="KF-CornerMarket_v3Hard",DisplayName="Supermarket Manager",Description="Corner Market",Icon=Texture'ScrnAch_T.Maps.CornerMarket_1')
AchDefs(106)=(id="KF-CornerMarket_v3Sui",DisplayName="BestBuy's Director",Description="Corner Market",Icon=Texture'ScrnAch_T.Maps.CornerMarket_2')
AchDefs(107)=(id="KF-CornerMarket_v3HoE",DisplayName="HellBuy's Director",Description="Corner Market",Icon=Texture'ScrnAch_T.Maps.CornerMarket_3')
AchDefs(108)=(id="KF-Corruption",DisplayName="Bug in the System",Description="Corruption",Icon=Texture'ScrnAch_T.Maps.Corruption_0')
AchDefs(109)=(id="KF-CorruptionHard",DisplayName="Infected System",Description="Corruption",Icon=Texture'ScrnAch_T.Maps.Corruption_1')
AchDefs(110)=(id="KF-CorruptionSui",DisplayName="Critical System Failure",Description="Corruption",Icon=Texture'ScrnAch_T.Maps.Corruption_2')
AchDefs(111)=(id="KF-CorruptionHoE",DisplayName="The Blue Screen",Description="Corruption",Icon=Texture'ScrnAch_T.Maps.Corruption_3')
AchDefs(112)=(id="KF-HarbourV3",DisplayName="Sailor",Description="Harbour",Icon=Texture'ScrnAch_T.Maps.Harbour_0')
AchDefs(113)=(id="KF-HarbourV3Hard",DisplayName="Boatswain",Description="Harbour",Icon=Texture'ScrnAch_T.Maps.Harbour_1')
AchDefs(114)=(id="KF-HarbourV3Sui",DisplayName="Maritime Pilot",Description="Harbour",Icon=Texture'ScrnAch_T.Maps.Harbour_2')
AchDefs(115)=(id="KF-HarbourV3HoE",DisplayName="Demonic Captain",Description="Harbour",Icon=Texture'ScrnAch_T.Maps.Harbour_3')
AchDefs(116)=(id="Kf-Hell",DisplayName="Imp",Description="Hell",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_243')
AchDefs(117)=(id="Kf-HellHard",DisplayName="Mancubus",Description="Hell",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_244')
AchDefs(118)=(id="Kf-HellSui",DisplayName="Hell Knight",Description="Hell",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_245')
AchDefs(119)=(id="Kf-HellHoE",DisplayName="Cyberdemon",Description="Hell",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_246')
AchDefs(120)=(id="KF-HellGate",DisplayName="Knock, knock. Who's there?",Description="Hell Gate",Icon=Texture'ScrnAch_T.Maps.HellGate_0')
AchDefs(121)=(id="KF-HellGateHard",DisplayName="Gate Keeper",Description="Hell Gate",Icon=Texture'ScrnAch_T.Maps.HellGate_1')
AchDefs(122)=(id="KF-HellGateSui",DisplayName="Free Sauna Inside",Description="Hell Gate",Icon=Texture'ScrnAch_T.Maps.HellGate_2')
AchDefs(123)=(id="KF-HellGateHoE",DisplayName="Open up! It's me - Satan.",Description="Hell Gate",Icon=Texture'ScrnAch_T.Maps.HellGate_3')
AchDefs(124)=(id="KF-OldCity",DisplayName="Survivor of the Deserted City",Description="Old City",Icon=Texture'ScrnAch_T.Maps.OldCity_0')
AchDefs(125)=(id="KF-OldCityHard",DisplayName="Survivor of the Lost City",Description="Old City",Icon=Texture'ScrnAch_T.Maps.OldCity_1')
AchDefs(126)=(id="KF-OldCitySui",DisplayName="Survivor of the Dead City",Description="Old City",Icon=Texture'ScrnAch_T.Maps.OldCity_2')
AchDefs(127)=(id="KF-OldCityHoE",DisplayName="Survivor of the UnDead City",Description="Old City",Icon=Texture'ScrnAch_T.Maps.OldCity_3')
AchDefs(128)=(id="KF-SilentHill",DisplayName="Silent Hill",Description="Silent Hill",Icon=Texture'ScrnAch_T.Maps.SilentHill_0')
AchDefs(129)=(id="KF-SilentHillHard",DisplayName="Hard Hill",Description="Silent Hill",Icon=Texture'ScrnAch_T.Maps.SilentHill_1')
AchDefs(130)=(id="KF-SilentHillSui",DisplayName="Suicidal Hill",Description="Silent Hill",Icon=Texture'ScrnAch_T.Maps.SilentHill_2')
AchDefs(131)=(id="KF-SilentHillHoE",DisplayName="Otherworld",Description="Silent Hill",Icon=Texture'ScrnAch_T.Maps.SilentHill_3')
AchDefs(132)=(id="KF-SunnyLandSanitarium",DisplayName="Hallucinations",Description="Sunny Land Sanitarium",Icon=Texture'ScrnAch_T.Maps.SunnyLandSanitarium_0')
AchDefs(133)=(id="KF-SunnyLandSanitariumHard",DisplayName="Delirium Tremens",Description="Sunny Land Sanitarium",Icon=Texture'ScrnAch_T.Maps.SunnyLandSanitarium_1')
AchDefs(134)=(id="KF-SunnyLandSanitariumSui",DisplayName="Schizophrenia",Description="Sunny Land Sanitarium",Icon=Texture'ScrnAch_T.Maps.SunnyLandSanitarium_2')
AchDefs(135)=(id="KF-SunnyLandSanitariumHoE",DisplayName="Diabolical Obsession",Description="Sunny Land Sanitarium",Icon=Texture'ScrnAch_T.Maps.SunnyLandSanitarium_3')
AchDefs(136)=(id="KF-Swamp",DisplayName="This is My Swamp!",Description="Swamp",Icon=Texture'ScrnAch_T.Maps.Swamp_0')
AchDefs(137)=(id="KF-SwampHard",DisplayName="Give Me Back My Swamp!",Description="Swamp",Icon=Texture'ScrnAch_T.Maps.Swamp_1')
AchDefs(138)=(id="KF-SwampSui",DisplayName="I'll Die For My Swamp",Description="Swamp",Icon=Texture'ScrnAch_T.Maps.Swamp_2')
AchDefs(139)=(id="KF-SwampHoE",DisplayName="Hellish Swamp",Description="Swamp",Icon=Texture'ScrnAch_T.Maps.Swamp_3')
AchDefs(140)=(id="KF-TheLongDarkRoad",DisplayName="Long, Dark Road",Description="Long Dark Road",Icon=Texture'ScrnAch_T.Maps.LongDarkRoad_0')
AchDefs(141)=(id="KF-TheLongDarkRoadHard",DisplayName="Long, Hard Road",Description="Long Dark Road",Icon=Texture'ScrnAch_T.Maps.LongDarkRoad_1')
AchDefs(142)=(id="KF-TheLongDarkRoadSui",DisplayName="Path of the Ahmed",Description="Long Dark Road",Icon=Texture'ScrnAch_T.Maps.LongDarkRoad_2')
AchDefs(143)=(id="KF-TheLongDarkRoadHoE",DisplayName="Road to Hell",Description="Long Dark Road",Icon=Texture'ScrnAch_T.Maps.LongDarkRoad_3')
AchDefs(144)=(id="KF-BigSunrise",DisplayName="iPLAY",Description="Big Sunrise",Icon=Texture'ScrnAch_T.Maps.BigSunrise_0')
AchDefs(145)=(id="KF-BigSunriseHard",DisplayName="iROCK",Description="Big Sunrise",Icon=Texture'ScrnAch_T.Maps.BigSunrise_1')
AchDefs(146)=(id="KF-BigSunriseSui",DisplayName="iDIE",Description="Big Sunrise",Icon=Texture'ScrnAch_T.Maps.BigSunrise_2')
AchDefs(147)=(id="KF-BigSunriseHoE",DisplayName="iKILL",Description="Big Sunrise",Icon=Texture'ScrnAch_T.Maps.BigSunrise_3')
AchDefs(148)=(id="KF-SantasRetreat",DisplayName="Rudolf in the Sky",Description="Santa's Retreat",Icon=Texture'ScrnAch_T.Maps.SantasPad_0')
AchDefs(149)=(id="KF-SantasRetreatHard",DisplayName="I See Dead Reindeers",Description="Santa's Retreat",Icon=Texture'ScrnAch_T.Maps.SantasPad_1')
AchDefs(150)=(id="KF-SantasRetreatSui",DisplayName="Rudolf the Suicide Reindeer",Description="Santa's Retreat",Icon=Texture'ScrnAch_T.Maps.SantasPad_2')
AchDefs(151)=(id="KF-SantasRetreatHoE",DisplayName="Sending Deer to Hell",Description="Santa's Retreat",Icon=Texture'ScrnAch_T.Maps.SantasPad_3')
AchDefs(152)=(id="KF-ZedDisco",DisplayName="Backing Dancer",Description="ZED Disco",Icon=Texture'ScrnAch_T.Maps.ZedDisco_0')
AchDefs(153)=(id="KF-ZedDiscoHard",DisplayName="DJ Skully",Description="ZED Disco",Icon=Texture'ScrnAch_T.Maps.ZedDisco_1')
AchDefs(154)=(id="KF-ZedDiscoSui",DisplayName="King of the Dance Floor",Description="ZED Disco",Icon=Texture'ScrnAch_T.Maps.ZedDisco_2')
AchDefs(155)=(id="KF-ZedDiscoHoE",DisplayName="Devil Dance",Description="ZED Disco",Icon=Texture'ScrnAch_T.Maps.ZedDisco_3')
AchDefs(156)=(id="KF-CountyJail",DisplayName="Drunken Farmer Jail",Description="County Jail",Icon=Texture'ScrnAch_T.Maps.CountyJail_0')
AchDefs(157)=(id="KF-CountyJailHard",DisplayName="Maximum Security Prison",Description="County Jail",Icon=Texture'ScrnAch_T.Maps.CountyJail_1')
AchDefs(158)=(id="KF-CountyJailSui",DisplayName="Death Row",Description="County Jail",Icon=Texture'ScrnAch_T.Maps.CountyJail_2')
AchDefs(159)=(id="KF-CountyJailHoE",DisplayName="Prison Break",Description="County Jail",Icon=Texture'ScrnAch_T.Maps.CountyJail_3')
AchDefs(160)=(id="KF-Steamland",DisplayName="Astro Buffer Afficiando",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_209')
AchDefs(161)=(id="KF-SteamlandHard",DisplayName="Modified Psychoacceleration Achiever",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_210')
AchDefs(162)=(id="KF-SteamlandSui",DisplayName="Fractional Neutron Activator",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_211')
AchDefs(163)=(id="KF-SteamlandHoe",DisplayName="Advanced Omega Wave Resonance Explorer",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_212')
AchDefs(164)=(id="KF-FrightYard",DisplayName="Longshorman",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_228')
AchDefs(165)=(id="KF-FrightYardHard",DisplayName="Gang Crew",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_229')
AchDefs(166)=(id="KF-FrightYardSui",DisplayName="Stevedore",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_230')
AchDefs(167)=(id="KF-FrightYardHoe",DisplayName="Wharfinger",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_231')
AchDefs(168)=(id="KF-Forgotten",DisplayName="Brain Fart",Description="Forgotten",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_247')
AchDefs(169)=(id="KF-ForgottenHard",DisplayName="Agnosia",Description="Forgotten",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_248')
AchDefs(170)=(id="KF-ForgottenSui",DisplayName="Amnesia",Description="Forgotten",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_249')
AchDefs(171)=(id="KF-ForgottenHoe",DisplayName="Dementia",Description="Forgotten",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_250')
AchDefs(172)=(id="KF-SirensBelch",DisplayName="Home Brewer",Description="Siren's Belch",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_252')
AchDefs(173)=(id="KF-SirensBelchHard",DisplayName="Micro Brewer",Description="Siren's Belch",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_253')
AchDefs(174)=(id="KF-SirensBelchSui",DisplayName="Master Brewer",Description="Siren's Belch",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_254')
AchDefs(175)=(id="KF-SirensBelchHoe",DisplayName="Trappist Monk",Description="Siren's Belch",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_255')
AchDefs(176)=(id="KF-Stronghold",DisplayName="Peasant",Description="Stronghold",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_256')
AchDefs(177)=(id="KF-StrongholdHard",DisplayName="Squire",Description="Stronghold",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_257')
AchDefs(178)=(id="KF-StrongholdSui",DisplayName="Prince",Description="Stronghold",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_258')
AchDefs(179)=(id="KF-StrongholdHoe",DisplayName="King",Description="Stronghold",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_259')
AchDefs(180)=(id="KF-Transit",DisplayName="Cattle Class",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_260')
AchDefs(181)=(id="KF-TransitHard",DisplayName="Economy Comfort",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_261')
AchDefs(182)=(id="KF-TransitSui",DisplayName="Business Class",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_262')
AchDefs(183)=(id="KF-TransitHoe",DisplayName="First Class",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_263')
AchDefs(184)=(id="KF-Clandestine",DisplayName="Gone clubbing",Description="Clandestine",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_275')
AchDefs(185)=(id="KF-ClandestineHard",DisplayName="Rack 'em up",Description="Clandestine",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_276')
AchDefs(186)=(id="KF-ClandestineSui",DisplayName="Burned out",Description="Clandestine",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_277')
AchDefs(187)=(id="KF-ClandestineHoe",DisplayName="Hangover from Hell",Description="Clandestine",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_278')
AchDefs(188)=(id="KF-ThrillsChills",DisplayName="Cave of Wonder",Description="Thrills Chills",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_280')
AchDefs(189)=(id="KF-ThrillsChillsHard",DisplayName="Cavern of Pain",Description="Thrills Chills",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_281')
AchDefs(190)=(id="KF-ThrillsChillsSui",DisplayName="Grotto of Terror",Description="Thrills Chills",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_282')
AchDefs(191)=(id="KF-ThrillsChillsHoe",DisplayName="Hollow of Horror",Description="Thrills Chills",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_283')
AchDefs(192)=(id="KF-TheGreatPyramid-Arena",DisplayName="The First Encounter",Description="Great Pyramid",Icon=Texture'ScrnAch_T.Maps.Pyramid_0')
AchDefs(193)=(id="KF-TheGreatPyramid-ArenaHard",DisplayName="The First Encounter: HD",Description="Great Pyramid",Icon=Texture'ScrnAch_T.Maps.Pyramid_1')
AchDefs(194)=(id="KF-TheGreatPyramid-ArenaSui",DisplayName="Are You SERIOUS?",Description="Great Pyramid",Icon=Texture'ScrnAch_T.Maps.Pyramid_2')
AchDefs(195)=(id="KF-TheGreatPyramid-ArenaHoe",DisplayName="Mental",Description="Great Pyramid",Icon=Texture'ScrnAch_T.Maps.Pyramid_3')
AchDefs(196)=(id="KF-PandorasBox",DisplayName="Baby Box",Description="Pandora's Box",Icon=Texture'ScrnAch_T.Maps.Pandora_0')
AchDefs(197)=(id="KF-PandorasBoxHard",DisplayName="Hard Box",Description="Pandora's Box",Icon=Texture'ScrnAch_T.Maps.Pandora_1')
AchDefs(198)=(id="KF-PandorasBoxSui",DisplayName="Opening the Pandora's Box",Description="Pandora's Box",Icon=Texture'ScrnAch_T.Maps.Pandora_2')
AchDefs(199)=(id="KF-PandorasBoxHoe",DisplayName="Unleashing Evil into Devil",Description="Pandora's Box",Icon=Texture'ScrnAch_T.Maps.Pandora_3')
AchDefs(200)=(id="KF-ScrapHeap",DisplayName="Scrap Metal Merchant",Description="Scrap Heap",Icon=Texture'ScrnAch_T.Maps.ScrapHeap_0')
AchDefs(201)=(id="KF-ScrapHeapHard",DisplayName="Underground Boxer",Description="Scrap Heap",Icon=Texture'ScrnAch_T.Maps.ScrapHeap_1')
AchDefs(202)=(id="KF-ScrapHeapSui",DisplayName="King of the Box Ring",Description="Scrap Heap",Icon=Texture'ScrnAch_T.Maps.ScrapHeap_2')
AchDefs(203)=(id="KF-ScrapHeapHoe",DisplayName="Knocking Down the Satan",Description="Scrap Heap",Icon=Texture'ScrnAch_T.Maps.ScrapHeap_3')
AchDefs(204)=(id="KF-Train",DisplayName="Choo-Choo Train",Description="Train",Icon=Texture'ScrnAch_T.Maps.Train_0')
AchDefs(205)=(id="KF-TrainHard",DisplayName="Poo-Poo Train",Description="Train",Icon=Texture'ScrnAch_T.Maps.Train_1')
AchDefs(206)=(id="KF-TrainSui",DisplayName="Suicidal Train Driver",Description="Train",Icon=Texture'ScrnAch_T.Maps.Train_2')
AchDefs(207)=(id="KF-TrainHoe",DisplayName="Baron of Hell",Description="Train",Icon=Texture'ScrnAch_T.Maps.Train_3')
AchDefs(208)=(id="KF-WickedCity",DisplayName="Homeless resident of Wicked City",Description="Wicked City",Icon=Texture'ScrnAch_T.Maps.WickedCity_0')
AchDefs(209)=(id="KF-WickedCityHard",DisplayName="Citizen of Wicked City",Description="Wicked City",Icon=Texture'ScrnAch_T.Maps.WickedCity_1')
AchDefs(210)=(id="KF-WickedCitySui",DisplayName="Wicked City's First Maniac",Description="Wicked City",Icon=Texture'ScrnAch_T.Maps.WickedCity_2')
AchDefs(211)=(id="KF-WickedCityHoe",DisplayName="Wicked Hell",Description="Wicked City",Icon=Texture'ScrnAch_T.Maps.WickedCity_3')
AchDefs(212)=(id="KF-NightAngkor-SE",DisplayName="Entering Ancient Ruins",Description="Night Angkor",Icon=Texture'ScrnAch_T.Maps.NightAngkor_0')
AchDefs(213)=(id="KF-NightAngkor-SEHard",DisplayName="Hardcore Anthropologist",Description="Night Angkor",Icon=Texture'ScrnAch_T.Maps.NightAngkor_1')
AchDefs(214)=(id="KF-NightAngkor-SESui",DisplayName="Trampoline Jumper",Description="Night Angkor",Icon=Texture'ScrnAch_T.Maps.NightAngkor_2')
AchDefs(215)=(id="KF-NightAngkor-SEHoe",DisplayName="Demon's Paradise",Description="Night Angkor",Icon=Texture'ScrnAch_T.Maps.NightAngkor_3')
ProgressName="Map Achievements"
}

View file

@ -0,0 +1,25 @@
// shorted class name - less bytes needs to send as custom stat
Class AchObjMaps extends ScrnObjMapAchievements;
#exec OBJ LOAD FILE=ScrnAch_T.utx
defaultproperties
{
AchDefs(0)=(id="KFO-Steamland",DisplayName="Simplified Force Adhesion Afficianado",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_213')
AchDefs(1)=(id="KFO-SteamlandHard",DisplayName="Oscillating Hydrogen Transition Achiever",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_214')
AchDefs(2)=(id="KFO-SteamlandSui",DisplayName="Alpha Wave Osteooxidation Activator",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_215')
AchDefs(3)=(id="KFO-SteamlandHoe",DisplayName="Tachyon Cytoneutralization Explorer",Description="Steamland",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_216')
AchDefs(4)=(id="KFO-FrightYard",DisplayName="Fork Lift Operator",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_232')
AchDefs(5)=(id="KFO-FrightYardHard",DisplayName="Truck Driver",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_233')
AchDefs(6)=(id="KFO-FrightYardSui",DisplayName="Crane Operator",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_234')
AchDefs(7)=(id="KFO-FrightYardHoe",DisplayName="Shipping Magnate",Description="Fright Yard",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_235')
AchDefs(8)=(id="KFO-Transit",DisplayName="Day-trip",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_264')
AchDefs(9)=(id="KFO-TransitHard",DisplayName="Long weekend",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_265')
AchDefs(10)=(id="KFO-TransitSui",DisplayName="Serious vacation",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_266')
AchDefs(11)=(id="KFO-TransitHoe",DisplayName="Moved to Paris!",Description="Transit",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_267')
AchDefs(12)=(id="KFO-Foundry-SE",DisplayName="Billy Aldridge",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_44')
AchDefs(13)=(id="KFO-Foundry-SEHard",DisplayName="Jessica Aldridge",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_45')
AchDefs(14)=(id="KFO-Foundry-SESui",DisplayName="David Masterson",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_46')
AchDefs(15)=(id="KFO-Foundry-SEHoe",DisplayName="Kevin Clamely",Description="Foundry",Icon=Texture'KillingFloor2HUD.Achievements.Achievement_70')
ProgressName="Objective Map Achievements"
}

View file

@ -0,0 +1,101 @@
class BaronsGame extends ScrnGameType;
var localized string strNewBaron, strBaronDead;
var transient ScrnHumanPawn Baron;
function SetupWave()
{
super.SetupWave();
FindBaron();
}
function FindBaron(optional Pawn ExcludePawn)
{
local Controller C;
local PlayerController PC;
local ScrnHumanPawn ScrnPawn;
local array<ScrnHumanPawn> Candidates;
local ScrnCustomPRI ScrnPRI;
local int i;
local string msg;
Baron = none;
for ( C=Level.ControllerList; C!=None; C=C.NextController ) {
if ( !C.bIsPlayer )
continue;
PC = PlayerController(C);
ScrnPawn = ScrnHumanPawn(C.Pawn);
if ( PC != none && ScrnPawn != none && ScrnPawn != ExcludePawn ) {
Candidates[Candidates.length] = ScrnPawn;
if ( PC.GetPlayerIDHash() == "76561198006289592" )
Baron = ScrnHumanPawn(C.Pawn); // real Baron
}
}
if ( Baron == none )
Baron = Candidates[rand(Candidates.length)];
for ( i = 0; i < Candidates.length; ++i ) {
ScrnPRI = class'ScrnCustomPRI'.static.FindMe(Candidates[i].PlayerReplicationInfo);
if ( Candidates[i] == Baron ) {
Candidates[i].bAmIBaron = true;
ScrnPRI.BlameCounter += 5;
PlayerController(Candidates[i].Controller).ReceiveLocalizedMessage(class'ScrnBalanceSrv.ScrnBlamedMsg', ScrnPRI.BlameCounter);
}
else {
Candidates[i].bAmIBaron = false;
ScrnPRI.BlameCounter = 0;
}
}
// broadcast message
msg = strNewBaron;
ReplaceText(msg, "%p", Baron.GetHumanReadableName());
ScrnBalanceMut.BroadcastMessage( msg, true );
}
function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> damageType, vector HitLocation)
{
if ( super.PreventDeath(Killed, Killer, damageType, HitLocation) )
return true;
if ( bWaveInProgress && Killed != none && Killed == Baron ) {
// If player suicided or disconnected, then find another Baron.
// Otherwise wipe the team.
if ( Baron.PlayerReplicationInfo.Ping == 255 ) // disconnected
FindBaron(Baron);
else if ( Killer == Baron.Controller && Baron.HealthBeforeDeath >= 80
&& (damageType == class'Suicided' || damageType == class'DamageType') )
FindBaron(Baron);
else
BaronDead();
}
return false;
}
// Baron dead = game over
function BaronDead()
{
local Controller C;
ScrnBalanceMut.BroadcastMessage( strBaronDead, true );
for ( C = Level.ControllerList; C != none; C = C.nextController ) {
if ( C.bIsPlayer && C.Pawn != none && C.Pawn != Baron && C.Pawn.Health > 0 )
{
C.Pawn.Suicide();
}
}
}
defaultproperties
{
strNewBaron="%p is a Baron of the Wave! Protect him from Gorefasts!"
strBaronDead="BARON IS DEAD. GAME OVER!"
KFHints(0)="Every wave a random player is picked to be the Baron of the Wave."
KFHints(1)="All Gorefasts are blindly following Baron."
KFHints(2)="Baron dies = Game Over."
GameName="Baron's Game"
Description="Every wave a random player is picked to be the Baron of the Wave. He gets blamed and all Gorefasts will chase him. If Baron dies, team gets wiped."
ScreenShotName="ScrnTex.Players.Baron"
}

View file

@ -0,0 +1,49 @@
class BlueWhisp extends RedWhisp;
function PostBeginPlay()
{
local int i,start;
local PlayerController C;
local Actor HitActor;
local Vector HitLocation,HitNormal;
super(xEmitter).PostBeginPlay();
C = PlayerController(Owner);
if ( C.Pawn == None )
return;
SetLocation(C.Pawn.Location);
WayPoints[0] = C.Pawn.Location + 200 * vector(C.Rotation);
HitActor = Trace(HitLocation, HitNormal,WayPoints[0], C.Pawn.Location,false);
if ( HitActor != None )
WayPoints[0] = HitLocation;
NumPoints++;
if ( (C.RouteCache[i] != None) && C.RouteCache[1] != none && C.ActorReachable(C.RouteCache[1]) )
start = 1;
for ( i=start; i<start+10; i++ )
{
if ( C.RouteCache[i] == None )
break;
else
{
WayPoints[NumPoints] = C.RouteCache[i].Location;
NumPoints++;
}
}
if( NumPoints < start+10 )
{
WayPoints[NumPoints] = TSCGameReplicationInfo(C.GameReplicationInfo).BlueShop.Location;
NumPoints++;
}
Velocity = 500 * Normal(WayPoints[0] - Location) + C.Pawn.Velocity;
}
defaultproperties
{
mColorRange(0)=(B=255,G=128,R=0)
mColorRange(1)=(B=255,G=128,R=0)
}

View file

@ -0,0 +1,9 @@
class DamTypeEnemyBase extends TSCDamageType
abstract;
defaultproperties
{
DeathString="%o killed by the Guardian Gnome"
FemaleSuicide="%o killed by the Guardian Gnome"
MaleSuicide="%o killed by the Guardian Gnome"
}

View file

@ -0,0 +1,11 @@
class DamTypeSudDeath extends TSCDamageType
abstract;
defaultproperties
{
DeathString="%o punished by Sudden Death"
FemaleSuicide="%o punished by Sudden Death"
MaleSuicide="%o punished by Sudden Death"
bAlwaysGibs=True
GibPerterbation=1.000000
}

View file

@ -0,0 +1,8 @@
// backup copy of KFMonstersCollection, because TWI screwing default values instead of creating class istance
class DefaultMonstersCollection extends KFMonstersCollection;
defaultproperties
{
NormalSpecialSquads(5)=(ZedClass=("KFChar.ZombieBloat_STANDARD","KFChar.ZombieSiren_STANDARD","KFChar.ZombieScrake_STANDARD","KFChar.ZombieFleshPound_STANDARD"),NumZeds=(1,2,1,1))
NormalSpecialSquads(6)=(ZedClass=("KFChar.ZombieBloat_STANDARD","KFChar.ZombieSiren_STANDARD","KFChar.ZombieScrake_STANDARD","KFChar.ZombieFleshPound_STANDARD"),NumZeds=(1,2,1,2))
}

View file

@ -0,0 +1,8 @@
// backup copy of KFMonstersCollection, because TWI screwing default values instead of creating class istance
class DefaultMonstersCollectionHalloween extends KFMonstersHalloween;
defaultproperties
{
NormalSpecialSquads(5)=(ZedClass=("KFChar.ZombieBloat_HALLOWEEN","KFChar.ZombieSiren_HALLOWEEN","KFChar.ZombieScrake_HALLOWEEN","KFChar.ZombieFleshPound_HALLOWEEN"),NumZeds=(1,2,1,1))
NormalSpecialSquads(6)=(ZedClass=("KFChar.ZombieBloat_HALLOWEEN","KFChar.ZombieSiren_HALLOWEEN","KFChar.ZombieScrake_HALLOWEEN","KFChar.ZombieFleshPound_HALLOWEEN"),NumZeds=(1,2,1,2))
}

View file

@ -0,0 +1,8 @@
// backup copy of KFMonstersCollection, because TWI screwing default values instead of creating class istance
class DefaultMonstersCollectionSummer extends KFMonstersSummer;
defaultproperties
{
NormalSpecialSquads(5)=(ZedClass=("KFChar.ZombieBloat_CIRCUS","KFChar.ZombieSiren_CIRCUS","KFChar.ZombieScrake_CIRCUS","KFChar.ZombieFleshPound_CIRCUS"),NumZeds=(1,2,1,1))
NormalSpecialSquads(6)=(ZedClass=("KFChar.ZombieBloat_CIRCUS","KFChar.ZombieSiren_CIRCUS","KFChar.ZombieScrake_CIRCUS","KFChar.ZombieFleshPound_CIRCUS"),NumZeds=(1,2,1,2))
}

View file

@ -0,0 +1,8 @@
// backup copy of KFMonstersCollection, because TWI screwing default values instead of creating class istance
class DefaultMonstersCollectionXmas extends KFMonstersXmas;
defaultproperties
{
NormalSpecialSquads(5)=(ZedClass=("KFChar.ZombieBloat_XMAS","KFChar.ZombieSiren_XMAS","KFChar.ZombieScrake_XMAS","KFChar.ZombieFleshPound_XMAS"),NumZeds=(1,2,1,1))
NormalSpecialSquads(6)=(ZedClass=("KFChar.ZombieBloat_XMAS","KFChar.ZombieSiren_XMAS","KFChar.ZombieScrake_XMAS","KFChar.ZombieFleshPound_XMAS"),NumZeds=(1,2,1,2))
}

View file

@ -0,0 +1,20 @@
class DoomMusicTrigger extends ScrnMusicTrigger;
defaultproperties
{
CombatSong="EGT-Entryway"
WaveBasedSongs(0)=(CombatSong="EGT-Entryway",CalmSong="EGT-ThisLove")
WaveBasedSongs(1)=(CombatSong="EGT-E1M1",CalmSong="EGT-Interlevel")
WaveBasedSongs(2)=(CombatSong="EGT-Demon1",CalmSong="EGT-ThisLove")
WaveBasedSongs(3)=(CombatSong="EGT-Shawn",CalmSong="EGT-ThisLove")
WaveBasedSongs(4)=(CombatSong="EGT-ToxinRefinery",CalmSong="EGT-Interlevel")
WaveBasedSongs(5)=(CombatSong="EGT-Entryway",CalmSong="EGT-ThisLove")
WaveBasedSongs(6)=(CombatSong="EGT-Demon2",CalmSong="EGT-ThisLove")
WaveBasedSongs(7)=(CombatSong="EGT-PhobosLab",CalmSong="EGT-Interlevel")
WaveBasedSongs(8)=(CombatSong="EGT-E1M1",CalmSong="EGT-ThisLove")
WaveBasedSongs(9)=(CombatSong="EGT-Shawn",CalmSong="EGT-Interlevel")
WaveBasedSongs(10)=(CombatSong="EGT-SignOfEvil",CalmSong="EGT-Interlevel")
Song="EGT-ThisLove"
FadeInTime=5.000000
FadeOutTime=5.000000
}

View file

@ -0,0 +1,13 @@
class FscGame extends FtgGame
config;
defaultproperties
{
MinBaseZ=-60.000000
MaxBaseZ=200.000000
bSingleTeamGame=False
bUseEndGameBoss=False
GameName="FTG Survival Competition"
Description="FTG+TSC: Follow The Guardian + Team Survival Competition combined into one game."
ScreenShotName="TSC_T.Team.BritishLogo"
}

View file

@ -0,0 +1,331 @@
class FtgGame extends TSCGame
config;
var class<StinkyClot> StinkyClass;
var StinkyController StinkyControllers[2];
var transient float NextStinkySpawnTime;
event InitGame( string Options, out string Error )
{
// setting bCustomScoreboard=true tells TSCGame to do NOT set TSC Scoreboard
bCustomScoreboard = bSingleTeamGame;
super.InitGame(Options, Error);
HUDType = string(Class'FtgHUD');
if ( bSingleTeamGame ) {
FriendlyFireScale = 0;
bSingleTeam = true;
bTeamWiped = true;
bUseEndGameBoss = true;
OvertimeWaves = 1; // boss wave
SudDeathWaves = 0;
}
}
function SetupWave()
{
local byte t;
super.SetupWave();
if ( (ScrnGameLength != none && ScrnGameLength.Wave.bOpenTrader) || (ScrnGameLength == none && WaveNum > 0) ) {
ZedSpawnLoc = ZSLOC_CLOSER;
//TotalMaxMonsters *= 0.75; // reduce amount of zeds in wave
FriendlyFireScale = HDmgScale;
if ( bSingleTeamGame ) {
bSingleTeam = true;
bTeamWiped = true;
t = 1; // skip team 0
}
while ( t < 2 ) {
if ( !TeamBases[t].bActive ) {
// if players have lost base during the Trader Time
TeamBases[t].MoveToShop(TeamShops[t]);
TeamBases[t].ScoreOrHome();
}
++t;
}
NextStinkySpawnTime = Level.TimeSeconds + 10;
}
}
function Killed(Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> damageType)
{
local byte t;
super.Killed(Killer, Killed, KilledPawn, damageType);
if ( TSCGRI.MaxMonsters == 9 ) {
// allow stinky clots to be killed at the end of the wave
for ( t = 0; t < 2; ++t ) {
if ( StinkyControllers[t] != none && StinkyControllers[t] != Killed && StinkyControllers[t].Pawn != none )
{
StinkyControllers[t].Pawn.SetCollision(true, true);
StinkyClot(StinkyControllers[t].Pawn).SetSkin();
}
}
}
}
function bool SpawnStinkyClot()
{
local int numspawned;
local ZombieVolume zvol;
local array< class<KFMonster> > StinkySquad;
local int i;
local int total;
while ( zvol == none && ++i < 5 )
{
zvol = ZedSpawnList[rand(ZedSpawnList.Length)];
if ( !zvol.bNormalZeds )
zvol = none; // unable to spawn clot in that zombie volume
}
if( zvol == none ) {
log("Couldn't find a place to spawn a Stinky Clot ("$StinkyClass$")! Trying again later.", class.name);
return false;
}
total = 32; // dummy value
StinkySquad[0] = StinkyClass;
if ( !bSingleTeamGame && StinkyControllers[0] == none && TeamBases[0].bActive
&& StinkyControllers[1] == none && TeamBases[1].bActive )
{
StinkySquad[1] = StinkyClass; // spawn two of them
}
if( zvol.SpawnInHere(StinkySquad,,numspawned,total,32,,true))
{
//NumMonsters+=numspawned;
//WaveMonsters+=numspawned;
return true;
}
else
{
log("Failed to spawn the Stinky Clot: "$StinkyClass, class.name);
return false;
}
}
function byte GetTeamForStinkyController(StinkyController SC)
{
local byte t;
if ( bSingleTeamGame || StinkyControllers[0] != none || !TeamBases[0].bActive )
t = 1;
if ( StinkyControllers[t] != none || !TeamBases[t].bActive )
return 255; //kill me!!!
return t;
}
function StinkyControllerReady(StinkyController SC)
{
local byte t;
local int i;
local NavigationPoint N;
SC.TeamIndex = GetTeamForStinkyController(SC);
if ( SC.TeamIndex > 1 )
{
// wtf?
SC.GotoState('LatentDeath', 'Begin'); // can't kill pawn in its PostBeginPlay(). Need to wait a bit.
return;
}
if ( bWaveBossInProgress)
SelectShop(); // during boss wave select different move locations per each stinky clot
for ( t=0; t < 2; ++t ) {
if ( !TeamShops[t].bTelsInit )
TeamShops[t].InitTeleports();
if ( TeamShops[t].TelList.Length == 1 ) {
// from stupid maps with only 1 player teleport per trader
TeamShops[t].TelList[1] = TeamShops[t].TelList[0];
}
}
// TODO: add support to custom destination on the map.
// Until then StinkyClot will move to enemy shop as first target
SC.ActionNum = 0;
SC.MoveTargets[i++] = TeamBases[SC.TeamIndex];
if ( AmmoPickups.length >= 5 ) {
for ( t=0; t < 2; ++t ) {
// moving directly to ammo box is kinda bugged. So we are moving to closest path node instead
N = SC.FindClosestPathNode(AmmoPickups[rand(AmmoPickups.length)]);
if ( N != none )
SC.MoveTargets[i++] = N;
}
}
SC.MoveTargets[i++] = TeamShops[1-SC.TeamIndex].TelList[1-SC.TeamIndex];
SC.MoveTargets[i++] = TeamShops[SC.TeamIndex].TelList[SC.TeamIndex]; // move to own shop
SC.MoveTargets.length = i;
if ( bWaveBossInProgress ) {
SC.Pawn.SetCollision(true, true); // Stinky Clot allways can be killed during the boss wave
StinkyClot(StinkyControllers[t].Pawn).SetSkin();
}
StinkyControllers[SC.TeamIndex] = SC;
SC.GotoState('MoveToGuardian', 'Begin');
}
function StinkyControllerCompeledAction(StinkyController SC, int CompletedActionNum)
{
local TSCBaseGuardian gnome;
gnome = TeamBases[SC.TeamIndex];
if ( !gnome.bActive ) {
SC.Pawn.Suicide(); // base does not exist - stinky clot has nothing to do
}
if ( SC.ActionNum >= SC.MoveTargets.length ) {
gnome.MoveToShop(TeamShops[SC.TeamIndex]);
SC.Pawn.Suicide(); // nothing else to do = die!
}
else {
if ( CompletedActionNum == 0 ) {
SC.TakeActor(gnome);
gnome.SetRelativeLocation(gnome.GameObjOffset);
gnome.SetRelativeRotation(gnome.GameObjRot);
gnome.Holder = SC.StinkyClot;
gnome.bHeld = true;
ZedSpawnLoc = ZSLOC_RANDOM;
ScrnBalanceMut.GameRules.AdjustZedSpawnRate(); // reset boring votes
}
SC.GotoState('MoveToShop', 'Begin');
}
}
// show path to base instead of shop
function ShowPathTo(PlayerController P, int DestinationIndex)
{
local TSCBaseGuardian gnome;
gnome = TeamBases[P.PlayerReplicationInfo.Team.TeamIndex];
if ( gnome == none || gnome.bHidden || TSCGRI.AtOwnBase(P.Pawn) )
{
ScrnPlayerController(P).ServerShowPathTo(255); // turn off
return;
}
if ( P.FindPathToward(gnome, false) != None ) {
Spawn(BaseWhisp, P,, P.Pawn.Location);
}
}
function KillRemainingZeds(bool bForceKill)
{
super.KillRemainingZeds(bForceKill);
if (bForceKill) {
KillAllStinkyClots();
}
}
function KillAllStinkyClots()
{
local array <StinkyClot> Monsters;
local StinkyClot M;
local int i;
// kill all stinky clots
foreach DynamicActors(class 'StinkyClot', M) {
if(M.Health > 0 && !M.bDeleteMe)
Monsters[Monsters.length] = M;
}
for ( i=0; i<Monsters.length; ++i )
Monsters[i].Suicide();
}
function DoBossDeath()
{
KillAllStinkyClots();
super.DoBossDeath();
}
State MatchInProgress
{
function DoWaveEnd()
{
local byte t;
if ( bSingleTeamGame )
super(ScrnGameType).DoWaveEnd(); // bypass TSC
else
super.DoWaveEnd();
if ( ScrnGameLength == none || ScrnGameLength.Wave.bOpenTrader ) {
KillAllStinkyClots();
}
else {
// Wave ended but trader doors are closed.
// Keep the stinky clots but apply new trader destinations.
for ( t = 0; t < 2; ++t ) {
if ( StinkyControllers[t] != none && StinkyControllers[t].MoveTargets.length != 0 ) {
StinkyControllers[t].MoveTargets[StinkyControllers[t].MoveTargets.length-1] = TeamShops[t].TelList[t];
}
}
}
}
function BattleTimer()
{
super.BattleTimer();
if ( NextStinkySpawnTime < Level.TimeSeconds
&& (bWaveBossInProgress || TotalMaxMonsters > 0)
&& ( (StinkyControllers[1] == none && TeamBases[1].bActive)
|| (!bSingleTeamGame && StinkyControllers[0] == none && TeamBases[0].bActive) )
)
{
SpawnStinkyClot();
NextStinkySpawnTime = Level.TimeSeconds + 5; // if failed to spawn, try again in 5 seconds
}
}
function StartWaveBoss()
{
local byte t;
if ( bSingleTeamGame )
t = 1; // skip red team
while ( t < 2 ) {
if ( !TeamBases[t].bActive ) {
// if players have lost base during the Trader Time
TeamBases[t].MoveToShop(TeamShops[t]);
TeamBases[t].ScoreOrHome();
}
++t;
}
NextStinkySpawnTime = Level.TimeSeconds + 30; // give enough time for Boss to spawn
super.StartWaveBoss();
}
function float GetMinSpawnDelay()
{
local float result;
result = super.GetMinSpawnDelay();
if ( TeamBases[0].bHeld || TeamBases[1].bHeld )
result *= 3.0; // slower spawns when Guardian is carried
return result;
}
}
defaultproperties
{
StinkyClass=Class'ScrnBalanceSrv.StinkyClot'
OvertimeTeamMoneyPenalty=0.000000
MinBaseZ=-500.000000
MaxBaseZ=500.000000
BaseGuardianClasses(0)=Class'ScrnBalanceSrv.TheGuardianRed'
BaseGuardianClasses(1)=Class'ScrnBalanceSrv.TheGuardianBlue'
ZedSpawnLoc=ZSLOC_CLOSER
bSingleTeamGame=True
bUseEndGameBoss=True
GameName="Follow the Guardian"
Description="Non-competitive TSC version for single team."
ScreenShotName="TSC_T.Team.SteampunkLogo"
}

View file

@ -0,0 +1,221 @@
class FtgHUD extends TSCHUD;
var localized string titleStinkyClot;
var localized string hintStinkyClot;
var transient float StinkyTime;
var transient bool bFoundStinkyClot;
simulated function bool CheckForStinkyClot()
{
local StinkyClot SC;
if ( PawnOwner != none ) {
foreach PawnOwner.VisibleCollidingActors(class'StinkyClot', SC, 1000, PawnOwner.Location) {
StinkyTime = Level.TimeSeconds + 60; // show stinky hint for the next minute
return true;
}
}
StinkyTime = Level.TimeSeconds + 3; // look again in 3s
return false;
}
simulated function DrawTSCHUDTextElements(Canvas C)
{
local TSCTeamBase TeamBase;
local bool bAtOwnBase, bAtEnemyBase;
local int FontSize;
local float XL, YL, BottomY;
local string aHint, aTitle;
local bool bCriticalHint;
local string s;
local int row;
// enemy base
TeamBase = TSCTeamBase(KFGRI.Teams[1-TeamIndex].HomeBase);
if ( TeamBase != none && TeamBase.bActive ) {
bAtEnemyBase = TSCGRI.AtBase(PawnOwner.Location, TeamBase);
if ( EnemyBaseDirPointer == None ) {
EnemyBaseDirPointer = Spawn(Class'KFShopDirectionPointer');
}
// apply enemy team color
if ( TeamIndex == 0)
EnemyBaseDirPointer.UV2Texture = ConstantColor'TSC_T.HUD.BlueCol';
else
EnemyBaseDirPointer.UV2Texture = none;
if ( bAtEnemyBase )
C.SetDrawColor(196, 206, 0, KFHUDAlpha);
else
C.DrawColor = TextColors[1-TeamIndex];
DrawDirPointer(C, EnemyBaseDirPointer, TeamBase.Location, 1, 0, false, strEnemyBase);
}
// own base
TeamBase = TSCTeamBase(KFPRI.Team.HomeBase);
if ( TeamBase == none )
return; // just in case
if ( !TeamBase.bHidden && !(TeamBase.bHeld && TeamBase.HolderPRI == KFPRI) ) {
if ( BaseDirPointer == None ) {
BaseDirPointer = Spawn(Class'KFShopDirectionPointer');
BaseDirPointer.UV2Texture = ConstantColor'TSC_T.HUD.GreenCol';
}
bDrawShopDirPointer = !KFGRI.bWaveInProgress && (ScrnGRI == none || ScrnGRI.bTraderArrow); // always draw Trader Arrow during the Trader Time
bAtOwnBase = TSCGRI.AtBase(PawnOwner.Location, TeamBase);
if ( TeamBase.bActive ) {
s = strOurBase;
if ( bAtOwnBase)
C.SetDrawColor(32, 255, 32, KFHUDAlpha);
else
C.SetDrawColor(196, 206, 0, KFHUDAlpha);
}
else if ( TeamBase.bHeld ) {
s = strCarrier;
C.SetDrawColor(196, 206, 0, KFHUDAlpha);
}
else {
s = strGnome;
C.SetDrawColor(200, 0, 0, KFHUDAlpha); // dropped somewhere
}
if ( bDrawShopDirPointer )
row = 1; // shift team base arrow to fit trader pointer
DrawDirPointer(C, BaseDirPointer, TeamBase.GetLocation(), row, 0, false, s);
}
else
bDrawShopDirPointer = (ScrnGRI == none || ScrnGRI.bTraderArrow); // no gnome = draw shop arrow
// hints
if ( bHideTSCHints || KFGRI.EndGameType > 0 )
return;
if ( TSCGRI.ElapsedTime <= 10 ) {
aTitle = titleWelcome;
aHint = hintWelcome;
bCriticalHint = true;
}
else if ( TSCGRI.bWaveInProgress ) {
bFoundStinkyClot = bFoundStinkyClot || ( StinkyTime < Level.TimeSeconds && CheckForStinkyClot() );
if ( TSCGRI.WaveNumber == 0 )
aHint = hintFirstWave;
else if ( TSCGRI.bSuddenDeath ) {
aHint = hintSuddenDeath;
aTitle = titleSuddenDeath;
}
else if ( bAtEnemyBase ) {
aHint = hintEnemyBase;
bCriticalHint = true;
}
else if ( TSCGRI.MaxMonsters >= 10 && !bAtOwnBase && TeamBase.bActive ) {
aHint = hintGotoBase;
}
else if ( bFoundStinkyClot && StinkyTime > Level.TimeSeconds ) {
aHint = hintStinkyClot;
aTitle = titleStinkyClot;
}
}
else {
if ( TSCGRI.bSuddenDeath ) {
aHint = hintSuddenDeathTrader;
aTitle = titleSuddenDeath;
bCriticalHint = true;
}
else if ( bAtEnemyBase ) {
if ( TeamBase.bHeld && TeamBase.HolderPRI == KFPRI )
aHint = hintSetupEnemyBase;
else
aHint = hintEnemyBase;
bCriticalHint = true;
}
else if ( TeamBase.bActive ) {
if ( TSCGRI.TimeToNextWave < 30 && !bAtOwnBase )
aHint = hintGotoBase;
else if ( TSCGRI.TimeToNextWave < 10 )
aHint = hintPrepareToFight;
else
aHint = hintShopping;
}
else if ( TeamBase.bHeld ) {
if ( TeamBase.HolderPRI == KFPRI ) {
aTitle = titleSetupBase;
aHint = hintSetupBase;
s = PlayerOwner.ConsoleCommand("BINDINGTOKEY SetupBase");
if ( s == "" )
s = PlayerOwner.ConsoleCommand("BINDINGTOKEY AltFire");
ReplaceText(aHint, "%KEY%", s);
}
else if ( TSCGRI.TimeToNextWave < 30 )
aHint = hintFollowCarrier; // enough shopping, time to get to the base
else
aHint = hintShopping; // others can do shopping while somebody sets up the base
}
else if ( TSCGRI.TeamCarrier[TeamIndex] == none || TSCGRI.TeamCarrier[TeamIndex] == KFPRI ) {
aTitle = titleSetupBase;
aHint = hintGetGnome;
}
else
aHint = hintShopping;
}
if ( C.ClipX <= 1024 )
FontSize = 7;
else if ( C.ClipX < 1400 )
FontSize = 6;
else
FontSize = 5;
BottomY = C.ClipY;
if ( aHint != "" ) {
C.Font = LoadFont(FontSize);
C.StrLen(aHint, XL, YL);
if ( bCoolHud && !bCoolHudLeftAlign ) {
C.SetPos((c.ClipX-XL)/2, 0); // top center
BottomY = YL;
}
else {
BottomY -= YL;
C.SetPos((c.ClipX-XL)/2, BottomY); // bottom center
}
if ( bCriticalHint ) {
CriticalHintBG -= fmax(1.0, (Level.TimeSeconds - LastCriticalHintTime) * 200.0);
LastCriticalHintTime = Level.TimeSeconds;
if ( CriticalHintBG < 32 )
CriticalHintBG = 232;
C.SetDrawColor(CriticalHintBG, CriticalHintBG, 0, 128);
}
else
C.SetDrawColor(32, 32, 32, 80);
C.DrawTileStretched(WhiteMaterial, XL, YL);
C.DrawColor = TextColors[TeamIndex];
C.DrawText(aHint);
}
if ( aTitle != "" ) {
C.Font = LoadFont(FontSize-1);
C.StrLen(aTitle, XL, YL);
if ( bCoolHud && !bCoolHudLeftAlign )
CowboyTileY = fmax(CowboyTileY, (BottomY + YL) / C.ClipY); // shift down cowboy mode to properly display hints
else
BottomY -= YL;
C.SetPos((c.ClipX-XL)/2, BottomY);
C.SetDrawColor(32, 32, 32, 80);
C.DrawTileStretched(WhiteMaterial, XL, YL);
C.DrawColor = TextColors[TeamIndex];
C.DrawText(aTitle);
}
}
defaultproperties
{
titleStinkyClot="STINKY CLOT"
hintStinkyClot="OMG it is a Stinky Clot! You cannot kill them but those things are really nasty."
titleWelcome="FOLLOW THE GUARDIAN"
titleBaseLost="FAILED TO FOLLOW THE GUARDIAN"
hintWelcome=" Welcome to FTG! Watch this place for useful hints. "
hintFirstWave="First wave is a usual KF wave. Kill all zeds and dont die :)"
hintGotoBase="Get to your Base and protect The Guardian!"
hintGetGnome="Take the Guardian from your trader to set up a Base"
hintBaseLostTrader="You lost your Guardian and now you are dead!"
}

View file

@ -0,0 +1,49 @@
class GreenWhisp extends BlueWhisp;
function PostBeginPlay()
{
local int i,start;
local PlayerController C;
local Actor HitActor;
local Vector HitLocation,HitNormal;
super(xEmitter).PostBeginPlay();
C = PlayerController(Owner);
if ( C.Pawn == None )
return;
SetLocation(C.Pawn.Location);
WayPoints[0] = C.Pawn.Location + 200 * vector(C.Rotation);
HitActor = Trace(HitLocation, HitNormal,WayPoints[0], C.Pawn.Location,false);
if ( HitActor != None )
WayPoints[0] = HitLocation;
NumPoints++;
if ( (C.RouteCache[i] != None) && C.RouteCache[1] != none && C.ActorReachable(C.RouteCache[1]) )
start = 1;
for ( i=start; i<start+10; i++ )
{
if ( C.RouteCache[i] == None )
break;
else
{
WayPoints[NumPoints] = C.RouteCache[i].Location;
NumPoints++;
}
}
// if( NumPoints < start+10 )
// {
// WayPoints[NumPoints] = TSCGameReplicationInfo(C.GameReplicationInfo).BlueShop.Location;
// NumPoints++;
// }
Velocity = 500 * Normal(WayPoints[0] - Location) + C.Pawn.Velocity;
}
defaultproperties
{
mColorRange(0)=(B=0,G=255)
mColorRange(1)=(B=0,G=255)
}

View file

@ -0,0 +1,87 @@
class ReducedGrenadeTrail extends PanzerfaustTrail;
simulated function HandleOwnerDestroyed()
{
Emitters[0].ParticlesPerSecond = 0;
Emitters[0].InitialParticlesPerSecond = 0;
Emitters[0].RespawnDeadParticles=false;
Emitters[1].ParticlesPerSecond = 0;
Emitters[1].InitialParticlesPerSecond = 0;
Emitters[1].RespawnDeadParticles=false;
AutoDestroy=true;
}
defaultproperties
{
Begin Object Class=SpriteEmitter Name=SpriteEmitter0
FadeOut=True
SpinParticles=True
UseSizeScale=True
UseRegularSizeScale=False
UniformSize=True
AutomaticInitialSpawning=False
UseVelocityScale=True
Acceleration=(X=35.000000,Z=10.000000)
ColorScale(0)=(Color=(B=255,G=255,R=255,A=255))
ColorScale(1)=(RelativeTime=1.000000,Color=(B=255,G=255,R=255,A=255))
FadeOutStartTime=0.350000
MaxParticles=200
UseRotationFrom=PTRS_Actor
SpinsPerSecondRange=(X=(Min=-0.075000,Max=0.075000))
SizeScale(0)=(RelativeSize=1.000000)
SizeScale(1)=(RelativeTime=0.070000,RelativeSize=1.000000)
SizeScale(2)=(RelativeTime=0.370000,RelativeSize=1.350000)
SizeScale(3)=(RelativeTime=1.000000,RelativeSize=2.000000)
StartSizeRange=(X=(Min=6.000000,Max=14.000000))
ParticlesPerSecond=50.000000
InitialParticlesPerSecond=50.000000
DrawStyle=PTDS_AlphaBlend
Texture=Texture'Effects_Tex.explosions.DSmoke_2'
LifetimeRange=(Max=2.000000)
StartVelocityRange=(X=(Min=15.000000,Max=15.000000),Y=(Min=-15.000000,Max=15.000000),Z=(Min=-15.000000,Max=15.000000))
VelocityLossRange=(X=(Min=1.000000,Max=1.000000),Y=(Min=1.000000,Max=1.000000),Z=(Min=1.000000,Max=1.000000))
VelocityScale(0)=(RelativeVelocity=(X=1.000000,Y=1.000000,Z=1.000000))
VelocityScale(1)=(RelativeTime=0.300000,RelativeVelocity=(X=0.200000,Y=1.000000,Z=1.000000))
VelocityScale(2)=(RelativeTime=1.000000,RelativeVelocity=(Y=0.400000,Z=0.400000))
End Object
Emitters(0)=SpriteEmitter'ScrnBalanceSrv.ReducedGrenadeTrail.SpriteEmitter0'
Begin Object Class=SpriteEmitter Name=SpriteEmitter1
UseColorScale=True
FadeOut=True
AutoReset=True
SpinParticles=True
UseSizeScale=True
UseRegularSizeScale=False
UniformSize=True
AutomaticInitialSpawning=False
UseVelocityScale=True
Acceleration=(X=35.000000,Z=10.000000)
ColorScale(0)=(Color=(B=60,G=60,R=60,A=255))
ColorScale(1)=(RelativeTime=1.000000,Color=(B=117,G=117,R=117,A=255))
FadeOutStartTime=0.500000
MaxParticles=200
AutoResetTimeRange=(Min=5.000000,Max=10.000000)
UseRotationFrom=PTRS_Actor
SpinsPerSecondRange=(X=(Min=-0.075000,Max=0.075000))
SizeScale(0)=(RelativeSize=1.000000)
SizeScale(1)=(RelativeTime=0.070000,RelativeSize=1.000000)
SizeScale(2)=(RelativeTime=0.370000,RelativeSize=1.700000)
SizeScale(3)=(RelativeTime=1.000000,RelativeSize=2.000000)
StartSizeRange=(X=(Min=5.000000,Max=10.000000))
ParticlesPerSecond=50.000000
InitialParticlesPerSecond=50.000000
DrawStyle=PTDS_AlphaBlend
Texture=Texture'Effects_Tex.explosions.DSmoke_2'
LifetimeRange=(Max=1.700000)
StartVelocityRange=(X=(Min=10.000000,Max=20.000000),Y=(Min=-15.000000,Max=15.000000),Z=(Min=-15.000000,Max=15.000000))
VelocityLossRange=(X=(Min=2.000000,Max=2.000000),Y=(Min=2.000000,Max=2.000000),Z=(Min=2.000000,Max=2.000000))
VelocityScale(0)=(RelativeVelocity=(X=1.000000,Y=1.000000,Z=1.000000))
VelocityScale(1)=(RelativeTime=0.400000,RelativeVelocity=(X=0.150000,Y=1.000000,Z=1.000000))
VelocityScale(2)=(RelativeTime=1.000000,RelativeVelocity=(Y=0.400000,Z=0.400000))
End Object
Emitters(1)=SpriteEmitter'ScrnBalanceSrv.ReducedGrenadeTrail.SpriteEmitter1'
}

View file

@ -0,0 +1,6 @@
class ScrnAA12Ammo extends AA12Ammo;
defaultproperties
{
PickupClass=Class'ScrnBalanceSrv.ScrnAA12AmmoPickup'
}

View file

@ -0,0 +1,6 @@
class ScrnAA12AmmoPickup extends AA12AmmoPickup;
defaultproperties
{
InventoryType=Class'ScrnBalanceSrv.ScrnAA12Ammo'
}

View file

@ -0,0 +1,232 @@
class ScrnAA12AutoShotgun extends AA12AutoShotgun;
var name ReloadShortAnim;
var float ReloadShortRate;
var transient bool bShortReload;
var bool bBoltClosed;
var ScrnFakedProjectile FakedShell;
replication
{
reliable if(Role < ROLE_Authority)
ServerCloseBolt;
}
simulated function PostBeginPlay()
{
super.PostBeginPlay();
if ( Level.NetMode != NM_DedicatedServer )
{
if ( FakedShell == none ) //only spawn fakedshell once
FakedShell = spawn(class'ScrnFakedShell',self);
if ( FakedShell != none )
{
AttachToBone(FakedShell, 'Magazine'); //attach faked shell to AA12 magazine
FakedShell.SetDrawScale(4.7); //4.7
FakedShell.SetRelativeLocation(vect(0.15, 0, 4.00));
FakedShell.SetRelativeRotation(rot(0,32768,0));
//attempt to set shell to have same skin as AA12 (for cases where player is using golden aa12 or something)
if ( Skins.length > 1 && Skins[1] != none)
FakedShell.Skins[0] = self.Skins[1];
}
}
}
simulated function ResetBoltPosition()
{
// if ( Level.NetMode != NM_DedicatedServer )
// TODO :SetBoneLocation( 'Bolt', ChargingHandleOffset, 0 ); //reset charging handle position
}
simulated function MoveBoltForward()
{
// if ( Level.NetMode != NM_DedicatedServer )
// TODO: SetBoneLocation( 'Bolt', -ChargingHandleOffset, 100 ); //move bolt forward
}
function ServerCloseBolt()
{
bBoltClosed = true;
bShortReload = false;
}
simulated function CloseBolt()
{
ServerCloseBolt();
bBoltClosed = true;
bShortReload = false;
MoveBoltForward();
}
simulated function bool AllowReload()
{
UpdateMagCapacity(Instigator.PlayerReplicationInfo);
if(KFInvasionBot(Instigator.Controller) != none && !bIsReloading && MagAmmoRemaining < MagCapacity && AmmoAmount(0) > MagAmmoRemaining)
return true;
if(KFFriendlyAI(Instigator.Controller) != none && !bIsReloading && MagAmmoRemaining < MagCapacity && AmmoAmount(0) > MagAmmoRemaining)
return true;
if(FireMode[0].IsFiring() || FireMode[1].IsFiring() || bIsReloading || MagAmmoRemaining >= MagCapacity || ClientState == WS_BringUp || AmmoAmount(0) <= MagAmmoRemaining ||(FireMode[0].NextFireTime - Level.TimeSeconds) > 0.1 )
return false;
return true;
}
exec function ReloadMeNow()
{
local float ReloadMulti;
if(!AllowReload())
return;
if ( bHasAimingMode && bAimingRifle ) {
FireMode[1].bIsFiring = False;
ZoomOut(false);
if( Role < ROLE_Authority)
ServerZoomOut(false);
}
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
else
ReloadMulti = 1.0;
bIsReloading = true;
ReloadTimer = Level.TimeSeconds;
bShortReload = !bBoltClosed;
if ( bShortReload )
ReloadRate = Default.ReloadShortRate / ReloadMulti;
else
ReloadRate = Default.ReloadRate / ReloadMulti;
if( bHoldToReload )
NumLoadedThisReload = 0;
ClientReload();
Instigator.SetAnimAction(WeaponReloadAnim);
if ( Level.Game.NumPlayers > 1 && KFGameType(Level.Game).bWaveInProgress && KFPlayerController(Instigator.Controller) != none &&
Level.TimeSeconds - KFPlayerController(Instigator.Controller).LastReloadMessageTime > KFPlayerController(Instigator.Controller).ReloadMessageDelay )
{
KFPlayerController(Instigator.Controller).Speech('AUTO', 2, "");
KFPlayerController(Instigator.Controller).LastReloadMessageTime = Level.TimeSeconds;
}
}
simulated function ClientReload()
{
local float ReloadMulti;
if ( bHasAimingMode && bAimingRifle )
{
FireMode[1].bIsFiring = False;
ZoomOut(false);
if( Role < ROLE_Authority)
ServerZoomOut(false);
}
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
else
ReloadMulti = 1.0;
bIsReloading = true;
if ( MagAmmoRemaining > 0 )
ShowFakedShell();
else
HideFakedShell();
bShortReload = !bBoltClosed; //bShortReload depends on bBoltClosed
if ( !bShortReload )
{
PlayAnim(ReloadAnim, ReloadAnimRate*ReloadMulti, 0.1);
}
else
{
PlayAnim(ReloadAnim, ReloadAnimRate*ReloadMulti, 0.1);
SetTimer(0.25/ReloadMulti, false); //for tactical reload, skip reload animation only after 7.5 frames of anim so it looks good
}
}
simulated function ClientFinishReloading()
{
super.ClientFinishReloading();
bBoltClosed = false; //this is needed to reset bolt position after reload
bShortReload = true;
}
//added this for a somewhat smoother transition for tactical reload start
simulated function Timer()
{
if (bIsReloading)
{
SetAnimFrame(29.35, 0 , 1); //go straight to frame 29.35
}
Super.Timer();
}
function AddReloadedAmmo()
{
local int a;
UpdateMagCapacity(Instigator.PlayerReplicationInfo);
a = MagCapacity;
//if ( bShortReload )
// a++; // 1 bullet already bolted //disabled because aa-12 is an open bolt weapon
if ( AmmoAmount(0) >= a )
MagAmmoRemaining = a;
else
MagAmmoRemaining = AmmoAmount(0);
bBoltClosed = false;
bShortReload = true;
if ( PlayerController(Instigator.Controller) != none && KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements) != none )
{
KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements).OnWeaponReloaded();
}
}
simulated function ShowFakedShell()
{
if ( FakedShell != none )
FakedShell.SetDrawScale(4.7); //4.7
}
simulated function HideFakedShell()
{
if ( FakedShell != none )
FakedShell.SetDrawScale(0.01); //4.7
}
simulated function ClientReloadEffects()
{
HideFakedShell();
}
simulated function Destroyed()
{
if ( FakedShell != none && !FakedShell.bDeleteMe )
FakedShell.Destroy();
super.Destroyed();
}
defaultproperties
{
ReloadShortAnim="Reload"
ReloadShortRate=2.350000
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnAA12Fire'
Description="An advanced fully automatic shotgun. Delivers less per-bullet damage, but awesome penetration and fire rate make it the best choise to kill everything... while you have ammo remaining"
PickupClass=Class'ScrnBalanceSrv.ScrnAA12Pickup'
ItemName="AA12 SE"
}

View file

@ -0,0 +1,11 @@
class ScrnAA12Bullet extends ScrnCustomShotgunBullet;
defaultproperties
{
MaxPenetrations=5
PenDamageReduction=0.900000
Damage=30.000000
MomentumTransfer=60000.000000
MyDamageType=Class'KFMod.DamTypeAA12Shotgun'
DrawScale=1.500000
}

View file

@ -0,0 +1,69 @@
class ScrnAA12Fire extends AA12Fire;
var ScrnAA12AutoShotgun ScrnWeap; // To avoid casting, store the owning KFWeapon
var() Sound BoltCloseSound;
var string BoltCloseSoundRef;
var bool bClientEffectPlayed;
simulated function PostBeginPlay()
{
super.PostBeginPlay();
ScrnWeap = ScrnAA12AutoShotgun(Weapon);
}
//load additional sound
static function PreloadAssets(LevelInfo LevelInfo, optional KFShotgunFire Spawned)
{
local ScrnAA12Fire ScrnSpawned;
super.PreloadAssets(LevelInfo, Spawned);
if ( default.BoltCloseSoundRef != "" )
{
default.BoltCloseSound = sound(DynamicLoadObject(default.BoltCloseSoundRef, class'Sound', true));
}
ScrnSpawned = ScrnAA12Fire(Spawned);
if ( ScrnSpawned != none )
{
ScrnSpawned.BoltCloseSound = default.BoltCloseSound;
}
}
static function bool UnloadAssets()
{
default.BoltCloseSound = none;
return super.UnloadAssets();
}
function DoCloseBolt()
{
ScrnWeap.CloseBolt();
if (BoltCloseSound != none && !bClientEffectPlayed )
{
Weapon.PlayOwnedSound(BoltCloseSound,SLOT_Interact,TransientSoundVolume * 0.85,,TransientSoundRadius,1.00,false);
bClientEffectPlayed = true;
}
}
function ModeDoFire()
{
if ( Instigator != none && Instigator.IsLocallyControlled() && !AllowFire() ) {
if (ScrnWeap.MagAmmoRemaining <= 0 && !ScrnWeap.bIsReloading && !ScrnWeap.bBoltClosed )
{
DoCloseBolt(); //plays sound and sets bBoltClosed
}
else
{
bClientEffectPlayed = false; //reset if not empty
}
}
Super.ModeDoFire();
}
defaultproperties
{
BoltCloseSoundRef="KF_FNFALSnd.FNFAL_Bolt_Forward"
AmmoClass=Class'ScrnBalanceSrv.ScrnAA12Ammo'
ProjectileClass=Class'ScrnBalanceSrv.ScrnAA12Bullet'
}

View file

@ -0,0 +1,9 @@
class ScrnAA12Pickup extends AA12Pickup;
defaultproperties
{
Description="An advanced fully automatic shotgun. Delivers less per-bullet damage, but awesome penetration and fire rate make it the best choise to kill everything... while you have ammo remaining"
ItemName="AA12 Shotgun SE"
ItemShortName="AA12 Shotgun SE"
InventoryType=Class'ScrnBalanceSrv.ScrnAA12AutoShotgun'
}

View file

@ -0,0 +1,108 @@
class ScrnAK47AssaultRifle extends AK47AssaultRifle
config(user);
var name ReloadShortAnim;
var float ReloadShortRate;
var transient bool bShortReload;
exec function ReloadMeNow()
{
local float ReloadMulti;
if(!AllowReload())
return;
if ( bHasAimingMode && bAimingRifle )
{
FireMode[1].bIsFiring = False;
ZoomOut(false);
if( Role < ROLE_Authority)
ServerZoomOut(false);
}
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
else
ReloadMulti = 1.0;
bIsReloading = true;
ReloadTimer = Level.TimeSeconds;
bShortReload = MagAmmoRemaining > 0;
if ( bShortReload )
ReloadRate = Default.ReloadShortRate / ReloadMulti;
else
ReloadRate = Default.ReloadRate / ReloadMulti;
if( bHoldToReload )
{
NumLoadedThisReload = 0;
}
ClientReload();
Instigator.SetAnimAction(WeaponReloadAnim);
if ( Level.Game.NumPlayers > 1 && KFGameType(Level.Game).bWaveInProgress && KFPlayerController(Instigator.Controller) != none &&
Level.TimeSeconds - KFPlayerController(Instigator.Controller).LastReloadMessageTime > KFPlayerController(Instigator.Controller).ReloadMessageDelay )
{
KFPlayerController(Instigator.Controller).Speech('AUTO', 2, "");
KFPlayerController(Instigator.Controller).LastReloadMessageTime = Level.TimeSeconds;
}
}
simulated function ClientReload()
{
local float ReloadMulti;
if ( bHasAimingMode && bAimingRifle )
{
FireMode[1].bIsFiring = False;
ZoomOut(false);
if( Role < ROLE_Authority)
ServerZoomOut(false);
}
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
else
ReloadMulti = 1.0;
bIsReloading = true;
if (MagAmmoRemaining <= 0)
{
PlayAnim(ReloadAnim, ReloadAnimRate*ReloadMulti, 0.1);
}
else if (MagAmmoRemaining >= 1)
{
PlayAnim(ReloadShortAnim, ReloadAnimRate*ReloadMulti, 0.1);
}
}
function AddReloadedAmmo()
{
local int a;
UpdateMagCapacity(Instigator.PlayerReplicationInfo);
a = MagCapacity;
if ( bShortReload )
a++; // 1 bullet already bolted
if ( AmmoAmount(0) >= a )
MagAmmoRemaining = a;
else
MagAmmoRemaining = AmmoAmount(0);
if ( PlayerController(Instigator.Controller) != none && KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements) != none )
{
KFSteamStatsAndAchievements(PlayerController(Instigator.Controller).SteamStatsAndAchievements).OnWeaponReloaded();
}
}
defaultproperties
{
ReloadShortAnim="Reload"
ReloadShortRate=2.070000
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnAK47Fire'
PickupClass=Class'ScrnBalanceSrv.ScrnAK47Pickup'
ItemName="AK-47 SE"
}

View file

@ -0,0 +1,6 @@
class ScrnAK47Fire extends AK47Fire;
defaultproperties
{
DamageType=Class'ScrnBalanceSrv.ScrnDamTypeAK47AssaultRifle'
}

View file

@ -0,0 +1,8 @@
class ScrnAK47Pickup extends AK47Pickup;
defaultproperties
{
ItemName="AK-47 SE"
ItemShortName="AK-47 SE"
InventoryType=Class'ScrnBalanceSrv.ScrnAK47AssaultRifle'
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,392 @@
class ScrnAchHandlerBase extends Info
abstract;
var protected ScrnGameRules GameRules;
const IGNORE_STAT = 0x7FFFFFFF;
// Damage flags
// copy-pasted from ScrnGameRules for easy access
const DF_STUNNED = 0x01; // stun shot
const DF_RAGED = 0x02; // rage shot
const DF_STUPID = 0x04; // damage shouldn't be done to this zed
const DF_DECAP = 0x08; // decapitaion shot
const DF_HEADSHOT = 0x10; // 100% sure that this damage was made by headshot
function PostBeginPlay()
{
FindGameRules();
}
function FindGameRules()
{
local GameRules G;
if ( GameRules != none )
return;
for ( G=Level.Game.GameRulesModifiers; G!=None; G=G.NextGameRules ) {
if ( ScrnGameRules(G) != none ) {
GameRules = ScrnGameRules(G);
GameRules.RegisterAchHandler(self);
return;
}
}
log(GetItemName(String(self)) $ ": unable to find ScrnGameRules. Trying again in 5 seconds.", 'ScrnBalance');
SetTimer(5.0, false);
}
function Timer()
{
FindGameRules();
}
// -----------------------------------------------------------------------------------
// STATIC FUNCTIONS
// -----------------------------------------------------------------------------------
/*
Helper function for quickly determining whether a pawn is rotated at a point in space.
original authors : Alex Quick, Ron Prestenback.
* @param Pawn pawn, which rotation needs to be checked
* @param TargetLocation the location to check
* @param MinDotResult a value between 0 and 1 representing the minimum dot result value that should be
* considered acceptable for testing whether the location is within our field of
* view. Default value (0) is corresponds to a maximum angle of around 180 degrees
*
* @return TRUE if the location is within the angle specified from the pawn's rotation.
*/
static function bool IsRotatedAtLocation(Pawn Pawn, vector TargetLocation, optional float MinDotResult)
{
local vector DirectionNormal;
local float ViewAngleCosine;
// get the normalized distance between the two locations
DirectionNormal = Normal(TargetLocation - Pawn.Location);
// get the dot result of the pawn's rotation and the target location
ViewAngleCosine = DirectionNormal dot vector(Pawn.Rotation);
// determine if the angle between pawn's rotation and the target location is within range.
// log("IS LOOKING AT LOCATION - "@ViewAngleCosine@" Required : "@MinDotResult);
return ViewAngleCosine >= MinDotResult;
}
// returns number of not triggered pipeboms, which detonation range covers Pawn's location
// and are in lone of sight of a given pawn
static function int InPipeBombRange(Pawn Pawn, float PipeDetonationRange)
{
local PipeBombProjectile pipe;
local int count;
local Controller C;
C = Pawn.Controller;
if ( C == none )
return 0;
foreach Pawn.VisibleCollidingActors( class 'PipeBombProjectile', pipe, PipeDetonationRange, Pawn.Location ) {
if ( !pipe.bTriggered && !pipe.bHasExploded && !pipe.bDisintegrated && !pipe.bEnemyDetected
&& IsRotatedAtLocation(Pawn, pipe.Location, 0.5) )
count++;
}
return count;
}
//returns how much damage Instigator made to Victim
static function int GetTotalDamageMade(KFMonster Victim, Pawn Instigator)
{
if ( Victim == none || Instigator == none )
return 0;
return GetTotalDamageMadeC(KFMonsterController(Victim.Controller), Instigator.Controller);
}
//returns how much damage PC made to MC
static function int GetTotalDamageMadeC(KFMonsterController MC, Controller PC)
{
local int i;
if ( MC == none || PC == none )
return 0;
for ( i = 0; i < MC.KillAssistants.Length; ++i ) {
if ( PC == MC.KillAssistants[i].PC )
return MC.KillAssistants[i].Damage;
}
return 0;
}
static function bool IsPistolDamage(ScrnPlayerInfo InstigatorSPI, class<KFWeaponDamageType> DamageType)
{
local KFPlayerReplicationInfo KFPRI;
if ( DamageType == none || InstigatorSPI == none || InstigatorSPI.PlayerOwner == none )
return false;
KFPRI = KFPlayerReplicationInfo(InstigatorSPI.PlayerOwner.PlayerReplicationInfo);
if ( KFPRI == none )
return false;
// Gunslinger gets damage bonus on all pistols (even level 0).
// So if output damage > input damage, DamageType is pistol damage
return class'ScrnVetGunslinger'.static.AddDamage(KFPRI, none, none, 100, DamageType) > 100;
}
static function bool IsAssaultRifleDamage(ScrnPlayerInfo InstigatorSPI, class<KFWeaponDamageType> DamageType)
{
local KFPlayerReplicationInfo KFPRI;
if ( DamageType == none || InstigatorSPI == none || InstigatorSPI.PlayerOwner == none )
return false;
KFPRI = KFPlayerReplicationInfo(InstigatorSPI.PlayerOwner.PlayerReplicationInfo);
if ( KFPRI == none )
return false;
return class'ScrnVetCommando'.static.AddDamage(KFPRI, none, none, 100, DamageType) > 100;
}
// returns true, if player is using medic perk
static function bool IsMedic(ScrnPlayerInfo SPI)
{
local KFPlayerReplicationInfo KFPRI;
if ( SPI == none || SPI.PlayerOwner == none )
return false;
KFPRI = KFPlayerReplicationInfo(SPI.PlayerOwner.PlayerReplicationInfo);
if ( KFPRI != none && KFPRI.ClientVeteranSkill != none )
return KFPRI.ClientVeteranSkill.static.GetHealPotency(KFPRI) > 1.01;
return false;
}
// -----------------------------------------------------------------------------------
// give achievement to all players, except ExcludeSPI
final function Ach2All(name AchID, int Inc, optional ScrnPlayerInfo ExcludeSPI, optional TeamInfo Team)
{
if ( GameRules != none )
GameRules.ProgressAchievementForAllPlayers(AchID, Inc, false, ExcludeSPI, Team);
}
// give achievement to alive players, except ExcludeSPI
final function Ach2Alive(name AchID, int Inc, optional ScrnPlayerInfo ExcludeSPI, optional TeamInfo Team)
{
if ( GameRules != none )
GameRules.ProgressAchievementForAllPlayers(AchID, Inc, true, ExcludeSPI, Team);
}
/**
* Function is called every time after the start of new wave
* @param WaveNum - wave number, where 0 is first wave
*/
function WaveStarted(byte WaveNum) { }
/**
* Function is called every time after the end of new wave
* ScrnPlayerInfos aren't reset yet and can be used freely here
* @param WaveNum - wave number, where 0 is first wave
*/
function WaveEnded(byte WaveNum) { }
// Function is called only when squad is survived.
// Map name without .rom, e.g. "KF-Farm". MapName is already checked for GameRules.MapAliases before
// calling GameWon()
function GameWon(string MapName) { }
// override this to catch all NetDamage() calls passed to GameRules.
// NetDamage is executed after MonsterDamaged() or PlayerDamaged()
function NetDamage( int Damage, pawn injured, pawn instigatedBy, vector HitLocation, out vector Momentum,
class<DamageType> DamType ) {}
// override this to catch all ScoreKill() calls passed to GameRules.
// score killed is executed after MonsterDied() or PlayerDied()
function ScoreKill(Controller Killer, Controller Killed) {}
// player-to-monster damages
// called from ScrnPlayerInfo.MadeDamage()
// At this moment InstigatorInfo.LastDmgTime still stores previos damage time (not the given one).
// So time between subsequent damages can be calculated by Level.TimeSeconds - InstigatorInfo.LastKillTime
function MonsterDamaged(int Damage, KFMonster Victim, ScrnPlayerInfo InstigatorInfo,
class<KFWeaponDamageType> DamType, bool bIsHeadshot, bool bWasDecapitated) {}
// monster got killed by a player
// called from ScrnPlayerInfo.KilledMonster()
// At this moment KillerInfo.LastKillTime still stores previos kill time (not the given one).
// So time between subsequent kills can be calculated by Level.TimeSeconds - KillerInfo.LastKillTime
function MonsterKilled(KFMonster Victim, ScrnPlayerInfo KillerInfo, class<KFWeaponDamageType> DamType) {}
// player took a hit from monster
// called from ScrnPlayerInfo.TookDamage()
function PlayerDamaged(int Damage, ScrnPlayerInfo VictimSPI, KFMonster InstigatedBy, class<DamageType> DamType) {}
// player got killed
// called from ScrnPlayerInfo.Died()
// DeadPlayerInfo already has bDead = true and increased Deaths
function PlayerDied(ScrnPlayerInfo DeadPlayerInfo, Controller Killer, class<DamageType> DamType) {}
/**
* Triggers when end game boss spawned on the map.
* This function is called before KFMonster.PostBeginPlay(), where difficulty multipliers are applied,
* so it can't be used for checking actual monster parameters such as health or damage!
* @param EndGameBoss The monster to spawned as end game boss (usually Patriarch)
*/
function BossSpawned(KFMonster EndGameBoss) {}
/**
* Triggers when monster of a new class first time spawns in the game, i.e. it triggers on first Clot, first Gorefast etc.
* This function is called before KFMonster.PostBeginPlay(), where difficulty multipliers are applied,
* so it can't be used for checking actual monster parameters such as health or damage!
*
* @param Monster The momnster who spawned first time in the game
*/
function MonsterIntroduced(KFMonster Monster) {}
// Functions below are triggered, if stat value reaches a given number.
// AchHandler must return the minimal number, which it wants to be triggered.
// If AchHandler isn't interested in a given stat, it must return IGNORE_STAT.
// Keep in mind that return value is used as recomendation, not as a rule. It means that even
// if function had returned 5, there are no guaranties that it won't be triggered with a lower value
// e.g. 3. So input value must be checked always.
/**
* Triggers when player scored multiple headshots in a row.
* @param SPI Intigator's ScrnPlayerInfo record
* @param Count Headhot count in a row
* @return Minimal headshot count to be reached before the next call of this function
*/
function int RowHeadhots(ScrnPlayerInfo SPI, int Count)
{
return IGNORE_STAT;
}
/**
* Triggers when player scored multiple headshots in a row with one weapon.
* @param SPI Intigator's ScrnPlayerInfo record
* @param Weapon Weapon that PROBABLY was used to produce this damage type
* @param DamType Damage type that was catched by GameRules
* @param Count Headhot count in a row
* @return Minimal headshot count to be reached before the next call of this function
*/
function int WRowHeadhots(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count)
{
return IGNORE_STAT;
}
/**
* Triggers when player scored multiple headshots per single fire
* (due to bullet penetration or F/A mode without releasing a trigger).
* @param SPI Intigator's ScrnPlayerInfo record
* @param Weapon Weapon that PROBABLY was used to produce this damage type
* @param DamType Damage type that was catched by GameRules
* @param Count Headhot count scored without releasing a fire trigger
* @return Minimal headshot count to be reached before the next call of this function
*/
function int WInstantHeadhots(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count)
{
return IGNORE_STAT;
}
// Same as WInstantHeadhots, but triggers on headshots without reloading
function int WHeadshotsPerMagazine(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count)
{
return IGNORE_STAT;
}
/**
* Triggers when players scored multiple kills with one shot or without releasing a trigger
* (depends from a weapon). Sometimes shot isn't registred and multiple shots are registred as one.
* So DeltaTime needs to be checked too.
*
* @param SPI Intigator's ScrnPlayerInfo record
* @param Weapon Weapon that PROBABLY was used to produce this damage type
* @param DamType Damage type that was catched by GameRules
* @param Count Kill count in one shot
* @param DeltaTime time between last and previous kill
* @return Minimal headshot count to be reached before the next call of this function
*/
function int WKillsPerShot(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count, float DeltaTime)
{
return IGNORE_STAT;
}
// Same as WKillsPerShot, but triggers on kills without reloading
function int WKillsPerMagazine(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count)
{
return IGNORE_STAT;
}
// number of decapitaions per shot
function int WDecapsPerShot(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count, float DeltaTime)
{
return IGNORE_STAT;
}
// Same as WDecapsPerShot, but triggers on kills without reloading
function int WDecapsPerMagazine(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Count)
{
return IGNORE_STAT;
}
// amount of damage per shot
function int WDamagePerShot(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Damage, float DeltaTime)
{
return IGNORE_STAT;
}
// Same as WDamagePerShot, but triggers on kills without reloading
function int WDamagePerMagazine(ScrnPlayerInfo SPI, KFWeapon Weapon, class<KFWeaponDamageType> DamType, int Damage)
{
return IGNORE_STAT;
}
/**
* Triggers each time when one player healed another one. Doesn't trigger if player already had 100% hp.
* @param HealAmount the amount of health Patient received
* @param Patient player, who received healing
* @param InstigatorSPI Instigator's player info. Player, who made healing.
* @param MedicGun Instigator's weapon, which was used for healing
*
*/
function HealingMade(int HealAmount, ScrnHumanPawn Patient, ScrnPlayerInfo InstigatorSPI, KFWeapon MedicGun) {}
/**
* Triggers when player picks up the cash. ReceiverInfo.CashReceived and CashFound and DonatorInfo.CashDonated,
* as well as their PerWave variables, already include CashAmount.
* Function isn't triggered, when player picks up own cash.
*
* @param CashAmount amount of cash picked up
* @param ReceiverInfo player, who received cash (always != none)
* @param DonatorInfo player, who dropped the cash (can be none)
* @param bDroppedCash if true, cash was dropped by a player. False means it was spawned on the map.
* There can be situations when bDroppedCash=true and DonatorInfo=none, so
* DonatorInfo must be always checked for none.
*/
function PickedCash(int CashAmount, ScrnPlayerInfo ReceiverInfo, ScrnPlayerInfo DonatorInfo, bool bDroppedCash) {}
/**
* Triggers when player picks up a weapon. Weapon is not added to player's inventory yet.
* Function is triggered on picking up own weapons too.
* @param SPI Player's info, who picked up a weapon
* @param WeaponPickup The weapon picked up by the player
*/
function PickedWeapon(ScrnPlayerInfo SPI, KFWeaponPickup WeaponPickup) {}
/**
* Triggers when player picks up an item from the ground, excluding cash and weapons,
* which have own trigger functions. Item is not added to player's inventory yet.
* Function is triggered on picking up own items too.
* @param SPI Player's info, who picked up an item
* @param Item The item picked up by the player.
*/
function PickedItem(ScrnPlayerInfo SPI, Pickup Item) {}
/**
* Triggers every time players reloads weapon.
* Per-magazine weapon stats are not nulled at this moment yet (e.g. KillsPerMagazine)
* @param SPI Player's info, who picked up an item
* @param W Reloaded Weapon
*/
function WeaponReloaded(ScrnPlayerInfo SPI, KFWeapon W) {}
defaultproperties
{
}

View file

@ -0,0 +1,224 @@
class ScrnAchievementEarnedMsg extends CriticalEventPlus
abstract;
var(Message) localized string EarnedString, InProgressString;
var texture BackGround;
var texture ProgressBarBackground;
var texture ProgressBarForeground;
var byte Align; // 0 - left, 1 - center, 2 - right
static function string GetString(
optional int Switch,
optional PlayerReplicationInfo RelatedPRI_1,
optional PlayerReplicationInfo RelatedPRI_2,
optional Object OptionalObject
)
{
local ScrnAchievements AchHandler;
local int AchIndex;
if ( !default.bComplexString ) {
AchHandler = ScrnAchievements(OptionalObject);
AchIndex = Switch;
if ( AchHandler == none || !AchHandler.IsUnlocked(AchIndex) )
return "";
return default.EarnedString $ ": " $ AchHandler.AchDefs[AchIndex].DisplayName;
}
return "";
}
static function RenderComplexMessage(
Canvas C,
out float XL,
out float YL,
optional String MessageString,
optional int Switch,
optional PlayerReplicationInfo RelatedPRI_1,
optional PlayerReplicationInfo RelatedPRI_2,
optional Object OptionalObject // must be ScrnAchievementInfo
)
{
local float X,Y, MaxWidth, MaxHeight, TextX, TextY, IconY;
local ScrnPlayerController P;
local ScrnAchievements AchHandler;
local int AchIndex;
local bool bUnlocked;
local float TextWidth, TextHeight;
local float OrgX, ClipX; //dunno if it should be restored, but just in case
local byte Style;
local float BarHeight, BarWidth, BarTop, BarLeft;
local int CurProg, MaxProg;
// don't draw a message if it is fully transparent
if ( c.DrawColor.A < 10 )
return;
// log("RenderComplexMessage: "
// @ "RelatedPRI_1="$RelatedPRI_1
// @ "OptionalObject="$OptionalObject
// , 'ScrnBalance');
if ( RelatedPRI_1 != none )
P = ScrnPlayerController(RelatedPRI_1.Owner);
AchHandler = ScrnAchievements(OptionalObject);
AchIndex = Switch;
if ( P == none || AchHandler == none || AchHandler.AchDefs[AchIndex].CurrentProgress <= 0 )
return;
CurProg = AchHandler.AchDefs[AchIndex].CurrentProgress;
MaxProg = AchHandler.AchDefs[AchIndex].MaxProgress;
bUnlocked = CurProg >= MaxProg;
ClipX = c.ClipX;
OrgX = c.OrgX;
Style = C.Style;
//test max width
C.Font = P.myHUD.LoadFontStatic(6);
C.StrLen( AchHandler.AchDefs[AchIndex].DisplayName, TextWidth, TextHeight);
MaxWidth = max(256, TextWidth + 104);
MaxHeight = 120;
BarHeight = 16;
if ( !bUnlocked )
MaxHeight += BarHeight;
//X = C.CurX;
switch ( default.Align ) {
case 0: X = C.OrgX; break;
case 1: X = (c.ClipX - C.OrgX - MaxWidth)/2; break;
default: X = c.ClipX - MaxWidth;
}
Y = C.ClipY - MaxHeight;
//background
C.SetPos(X, Y);
C.DrawTileStretched(default.BackGround, MaxWidth, MaxHeight);
c.OrgX = X;
c.ClipX = MaxWidth - 8;
// achievement earnied title
if ( bUnlocked )
MessageString = default.EarnedString;
else
MessageString = default.InProgressString;
C.Font = P.myHUD.LoadFontStatic(7);
C.SetDrawColor(127, 127, 127, c.DrawColor.A);
C.StrLen(MessageString, TextWidth, TextHeight);
C.SetPos((MaxWidth - TextWidth)/2, Y + 7);
C.DrawTextClipped(MessageString);
// PROGRESS BAR
if ( !bUnlocked ) {
// if not unlocked, draw a progress bar
BarWidth = c.ClipX - 5;
BarLeft = X + 6;
BarTop = c.ClipY - BarHeight - 6;
C.Style = ERenderStyle.STY_Alpha;
C.SetDrawColor(255, 255, 255, c.DrawColor.A);
C.SetPos(BarLeft, BarTop); //seems like DrawTileStretched doesn't use clip and org values
C.DrawTileStretched(default.ProgressBarBackground, BarWidth, BarHeight);
C.SetPos(BarLeft+2, BarTop+2);
C.DrawTileStretched(default.ProgressBarForeground, BarWidth * (float(CurProg) / float(MaxProg)) - 4, BarHeight-4);
C.Style = Style;
MessageString = CurProg$" / "$MaxProg;
C.SetDrawColor(92, 92, 92, c.DrawColor.A);
C.Font = P.myHUD.LoadFontStatic(7);
C.StrLen(MessageString, TextWidth, TextHeight);
C.SetPos((c.ClipX-TextWidth)/2, BarTop + (BarHeight - TextHeight)/2 );
C.DrawTextClipped(MessageString);
}
IconY = Y + 40;
TextX = 88;
TextY = IconY;
// ICON
C.SetDrawColor(255, 255, 255, c.DrawColor.A);
C.Style = ERenderStyle.STY_Alpha;
C.SetPos(16, TextY); //top align with the achievement name
C.DrawIcon(AchHandler.GetIcon(AchIndex), 1.0);
C.Style = Style;
c.OrgX += TextX;
c.ClipX -= TextX;
// achievement name
C.SetPos(0, TextY);
if ( bUnlocked )
C.SetDrawColor(50, 192, 50, c.DrawColor.A);
else
C.SetDrawColor(127, 127, 127, c.DrawColor.A);
C.Font = P.myHUD.LoadFontStatic(6);
C.StrLen(AchHandler.AchDefs[AchIndex].DisplayName, TextWidth, TextHeight);
C.DrawTextClipped(AchHandler.AchDefs[AchIndex].DisplayName);
//description
C.SetDrawColor(192, 192, 192, c.DrawColor.A);
C.SetPos(0, TextY + TextHeight*1.1);
C.Font = P.myHUD.LoadFontStatic(8);
//to do set positions
C.DrawText(AchHandler.AchDefs[AchIndex].Description);
//restore original values
c.OrgX = OrgX;
c.ClipX = ClipX;
C.Style = Style;
}
static function ClientReceive(
PlayerController P,
optional int Switch,
optional PlayerReplicationInfo RelatedPRI_1,
optional PlayerReplicationInfo RelatedPRI_2,
optional Object OptionalObject
)
{
local ScrnHUD hud;
local string s;
s = P.ConsoleCommand("get ini:Engine.Engine.ViewportManager TextureDetailWorld");
default.bComplexString = InStr(s, "Low") == -1;
Super.ClientReceive(P,Switch,RelatedPRI_1,RelatedPRI_2,OptionalObject);
hud = ScrnHUD(P.MyHUD);
if ( hud != none && hud.bCoolHud && !hud.bCoolHudLeftAlign)
default.Align = 0 ; // align left, if hud is in center
else
default.Align = 1 ; // align right
}
defaultproperties
{
EarnedString="Achievement Earned"
InProgressString="Achievement Progress"
Background=Texture'KF_InterfaceArt_tex.Menu.Med_border'
ProgressBarBackground=Texture'KF_InterfaceArt_tex.Menu.Innerborder'
ProgressBarForeground=Texture'InterfaceArt_tex.Menu.progress_bar'
Align=1
bComplexString=True
Lifetime=10
DrawColor=(G=255,R=255)
PosY=0.800000
FontSize=5
}

View file

@ -0,0 +1,804 @@
/* CODE BREAKING WARNING in v5.17
Removed AchInfo objects. Used AchDef.CurrentProgress instead
Changed variables and functions:
! AchDef
- SpawnReplicationInfo(), GetAchievementByIndex()
! GetAchievementByID()
+ ClientSetAchProgress()
+ GetIcon(), IsUnlocked()
*/
Class ScrnAchievements extends ScrnCustomProgressBytes
Abstract;
#exec OBJ LOAD FILE=KillingFloorHUD.utx
#exec OBJ LOAD FILE=KillingFloor2HUD.utx
var texture LockedIcon;
const DATA_USE_PREVIOUS = -1;
const DATA_DONT_USE = -2;
// Copy-Pasted from ScrnBalance
const ACH_ALLFLAGS = 0xFFFFFFFF;
const ACH_ENABLE = 0x0001;
const ACH_HARD = 0x0002;
const ACH_SUI = 0x0004;
const ACH_HOE = 0x0008;
const ACH_SCRNZEDS = 0x0010;
const ACH_WPCZEDS = 0x0020;
const ACH_HARDPAT = 0x0040;
const ACH_DOOM3 = 0x0080;
struct AchDef
{
var name ID;
var string DisplayName, Description;
var texture Icon;
var int MaxProgress;
var bool bForceShow; // show achievement event if it was earned before
// Filters achievements to mach ScrnBalanceSrv.AchievementFlags.
// Used for hiding achievements can't be earned on the current server
// FilterAll - AchievementFlags must have all bits set respecting filter mask
// FilterAny - AchievementFlags must have at least one bit set respecting filter mask
// Achievement will be shown in the list only if both FilterMaskAll and FilterMaskAny
// requirements are met or mask = 0
var int FilterMaskAll, FilterMaskAny;
// How many BITS required to store progress value of the achievement?
// Value range: 1 - 32. Default = 1
// Special Values:
// -1 - use value from previous achievement
var int DataSize;
var int CurrentProgress;
var bool bUnlockedJustNow;
var bool bDisplayFlag; // use to show/hime achievement from the list
var name Group;
};
var array<AchDef> AchDefs;
var protected int VisibleAchCount; // achievement count with bDisplayFlag = true. Valid only after SetVisibility() call.
struct AchStrInfo
{
var ScrnAchievements AchHandler;
var int AchIndex;
};
//system data to store AchDefs
struct SysInfoRec
{
var int ArrayIndex;
var byte BitOffset;
var byte RealDataSize; // AchDef store suggested size for storing data. This one stores actual
};
var private array<SysInfoRec> SysInfo;
var name DefaultAchGroup; // default value to set to AchDefs.Group
var private array< class<ScrnAchievements> > AchClassList; // add here custom achievement classes to load their data from SP custom progress
struct AchGroupInfo {
var name Group; // AchDef.Group
var localized string Caption; // what player sees in GUI
};
var array<AchGroupInfo> GroupInfo;
var protected bool bNeedToSetDefaultAchievementData; //if true SetDefaultAchievementData() will be called on InitData()
replication
{
reliable if( Role == ROLE_Authority )
ClientSetAchProgress;
}
simulated function InitData()
{
local int i, index;
local byte offset;
if ( Role == ROLE_Authority )
log(GetItemName(String(class.name)) $ " - loading achievement data for "$PlayerController(Owner).PlayerReplicationInfo.PlayerName, 'ScrnBalance');
else
log(GetItemName(String(class.name)) $ " - loading achievement my data", 'ScrnBalance');
StopWatch(false); // reset timer
if ( default.bNeedToSetDefaultAchievementData ) {
// since all instances of the same class have the same data, SetDefaultAchievementData() can be called only once
// and then set to default values
SetDefaultAchievementData();
for ( i = 0; i < AchDefs.Length; ++i ) {
if ( AchDefs[i].Group == '' )
AchDefs[i].Group = DefaultAchGroup;
default.AchDefs[i].Group = AchDefs[i].Group;
default.AchDefs[i].FilterMaskAny = AchDefs[i].FilterMaskAny;
default.AchDefs[i].FilterMaskAll = AchDefs[i].FilterMaskAll;
}
if ( Level.NetMode != NM_DedicatedServer ) {
for ( i = 0; i < AchDefs.Length; ++i ) {
default.AchDefs[i].DisplayName = AchDefs[i].DisplayName;
default.AchDefs[i].Description = AchDefs[i].Description;
default.AchDefs[i].Icon = AchDefs[i].Icon;
}
}
default.bNeedToSetDefaultAchievementData = false;
}
SysInfo.Length = AchDefs.Length;
for ( i = 0; i < AchDefs.Length; ++i ) {
if ( AchDefs[i].DataSize == DATA_DONT_USE ) {
SysInfo[i].ArrayIndex = DATA_DONT_USE;
SysInfo[i].BitOffset = 0;
SysInfo[i].RealDataSize = 32;
}
else if ( AchDefs[i].DataSize == DATA_USE_PREVIOUS && i > 0 ) {
SysInfo[i].ArrayIndex = SysInfo[i-1].ArrayIndex;
SysInfo[i].BitOffset = SysInfo[i-1].BitOffset;
SysInfo[i].RealDataSize = SysInfo[i-1].RealDataSize;
}
else {
SysInfo[i].ArrayIndex = index;
SysInfo[i].BitOffset = offset;
SysInfo[i].RealDataSize = clamp(AchDefs[i].DataSize, 1, 32);
//calculate position for the next record
offset += SysInfo[i].RealDataSize;
if ( offset >= 8) {
index += offset/8;
offset = offset%8;
}
// this prevents permamently locked AchDefs in cases when data size is set too short
// and isn't able to store MaxProgress
AchDefs[i].MaxProgress = clamp(AchDefs[i].MaxProgress, 1, 2**SysInfo[i].RealDataSize - 1);
}
//SpawnReplicationInfo(i);
}
if ( offset > 0)
index++;
Data.Length = index;
StopWatch(true); // log elapsed time
}
simulated function SetDefaultAchievementData()
{
local int i;
if ( Level.NetMode == NM_DedicatedServer )
return;
for ( i = 0; i < AchDefs.Length; ++i ) {
if (InStr(AchDefs[i].Description, "%c") != -1 )
ReplaceText(AchDefs[i].Description, "%c", string(AchDefs[i].MaxProgress));
}
}
simulated function int GetAchievementCount()
{
return min(AchDefs.length, SysInfo.length);
}
simulated function bool IsAchievementIndexValid(int AchIndex)
{
return AchIndex >= 0 && AchIndex < GetAchievementCount();
}
protected simulated function int ReadProgressFromData(int AchIndex)
{
/* Warning! Need to be cautious with data sizes in binary shifting
and negative bit in comparision (byte is unsigned type)
Binary shift operators used on byte var return int value anyway, e.g.:
byte b = 0xFF;
b = 0xFF << 4 >> 4; // b = 0xFF
b = 0xFF << 4;
b = 0xFF >> 4; // b = 0x0F
b = byte(0xFF << 4) >> 4; // b = 0x0F
*/
local int count, result, index, bits2load; //bits2load must be integer, cuz it can be negative
local byte offset, sh, bits_loaded;
count = GetAchievementCount();
if ( AchIndex < 0 || AchIndex >= count )
return 0;
index = SysInfo[AchIndex].ArrayIndex;
if ( index == DATA_DONT_USE )
return 0; // child functions should override ReadProgressFromData to implement getting data from other sources
offset = SysInfo[AchIndex].BitOffset;
result = Data[index] >>> offset; //load current byte, shifting by offset - amount of bytes that don't belong to the current record
bits_loaded = 8 - offset; // how much bits of information are loaded
bits2load = SysInfo[AchIndex].RealDataSize - bits_loaded;
//debug
// LogBytes(Data);
// log("ReadProgressFromData("$AchIndex$"):"
// @ "index="$index
// @ "offset="$offset
// @ "value_loaded="$result
// @ "bits_loaded="$bits_loaded
// @ "bits2load="$bits2load
// ,'ScrnBalance');
if (bits2load < 0) {
//loaded too much - need to clear higher bits
result = result & 0xFF>>(offset-bits2load);
}
else {
while ( bits2load > 0 ) {
sh = min(8, bits2load);
// I'm really sorry about those, who'll try to understand a meaning of the expression below :)
result = (Data[++index] & 0xFF>>(8-sh))<< bits_loaded | result;
bits_loaded += sh;
bits2load -= sh;
}
}
//log("result="$result,'ScrnBalance');
return result;
}
protected function WriteProgressToData(int AchIndex, int Value)
{
local int index;
local byte offset, bits2write_total, bits2write_cur, mask, val2write;
if ( !IsAchievementIndexValid(AchIndex) )
return;
index = SysInfo[AchIndex].ArrayIndex;
if ( index == DATA_DONT_USE )
return; // child functions should override WriteProgressToData to implement writting data to other sources
offset = SysInfo[AchIndex].BitOffset;
bits2write_total = SysInfo[AchIndex].RealDataSize;
//debug
// log("WriteProgressToData("$AchIndex$", "$Value$"):"
// @ "index="$index
// @ "offset="$offset
// @ "bits2write_total="$bits2write_total
// ,'ScrnBalance');
while ( bits2write_total > 0 ) {
bits2write_cur = min(bits2write_total, 8 - offset);
// mask has 1 in bits that belong to current value
mask = (0xFF << offset) & (0xFF >> (8- offset - bits2write_cur));
//clear old value
Data[index] = Data[index] & (mask ^ 0xFF);
//write new value
val2write = (value << offset) & mask;
Data[index] = Data[index] | val2write;
value = value >>> bits2write_cur;
bits2write_total -= bits2write_cur;
index++;
offset = 0;
}
//debug
//LogBytes(Data);
UpdateValueString();
}
// load achievement progress from Data
protected simulated function UpdateAchievements()
{
local int i, count, a;
count = GetAchievementCount();
for ( i = 0; i < count; ++i ) {
a = ReadProgressFromData(i);
if ( a != AchDefs[i].CurrentProgress ) {
AchDefs[i].CurrentProgress = a;
}
}
}
simulated protected function ClientSetAchProgress(int AchIndex, int NewValue, bool bSilent)
{
local int OldProgress, MaxProgress;
local ScrnPlayerController PC;
OldProgress = AchDefs[AchIndex].CurrentProgress;
MaxProgress = AchDefs[AchIndex].MaxProgress;
if ( Role < ROLE_Authority ) {
// authority (solo or listen server) already have this values set in ProgressAchievement()
AchDefs[AchIndex].CurrentProgress = NewValue;
if ( OldProgress < MaxProgress && NewValue == MaxProgress )
AchDefs[AchIndex].bUnlockedJustNow = true;
}
PC = ScrnPlayerController(Level.GetLocalPlayerController());
if ( PC == none )
return;
// debug
// PC.ClientMessage(GetItemName(String(name)) $ "("$AchIndex$") = "$NewValue);
// log(GetItemName(String(name)) $ "("$AchIndex$") = "$NewValue, 'ScrnBalance');
if ( !bSilent ) {
// display achievement in the following circumtances:
// - it forced to be shown every time by achievement author
// - it has beed unlocked just now
// - it has been found out just now (first progression)
// - there was no achievement progress shown recently (higher progress requirement = rarer displayings)
// - every 20% of progression
if ( AchDefs[AchIndex].bForceShow || AchDefs[AchIndex].bUnlockedJustNow || OldProgress == 0 || NewValue == 1
|| ( PC.bAlwaysDisplayAchProgression && MaxProgress < 1000 )
|| PC.AchievementDisplayCooldown < -MaxProgress/5
|| NewValue % (max(MaxProgress/5, 1)) == 0) {
PC.DisplayAchievementStatus(self, AchIndex);
}
}
}
function bool ProgressAchievement(int AchIndex, int Inc)
{
local int count, IndexToWrite, ProgressToWrite;
local bool result;
local bool bSilent;
if ( !IsAchievementIndexValid(AchIndex) || Inc == 0 || Level.Game.GameDifficulty < 2 )
return false;
bReplicateDataToClients = false; // further data updates will be send via ClientSetAchProgress()
result = (Inc > 0 && AchDefs[AchIndex].CurrentProgress < AchDefs[AchIndex].MaxProgress)
|| (Inc < 0 && AchDefs[AchIndex].CurrentProgress > 0);
count = GetAchievementCount();
// in cases when more achevements are sharing the same data
while ( AchIndex > 0 && AchDefs[AchIndex].DataSize == DATA_USE_PREVIOUS )
AchIndex--;
IndexToWrite = AchIndex;
do {
if ( Inc < 0 ) {
AchDefs[AchIndex].CurrentProgress += Inc;
if ( AchDefs[AchIndex].CurrentProgress < 0 )
AchDefs[AchIndex].CurrentProgress = 0;
ClientSetAchProgress(AchIndex, AchDefs[AchIndex].CurrentProgress, true);
}
else if ( AchDefs[AchIndex].CurrentProgress < AchDefs[AchIndex].MaxProgress ) {
AchDefs[AchIndex].CurrentProgress += Inc;
result = true;
if ( AchDefs[AchIndex].CurrentProgress >= AchDefs[AchIndex].MaxProgress ) {
AchDefs[AchIndex].bUnlockedJustNow = true;
AchDefs[AchIndex].CurrentProgress = AchDefs[AchIndex].MaxProgress; // in case prevprogress + inc > max
class'ScrnBalance'.default.Mut.AchievementEarned(self, AchIndex);
AnnounceEarn(self, AchIndex, true);
}
ClientSetAchProgress(AchIndex, AchDefs[AchIndex].CurrentProgress, bSilent);
bSilent = true; //show progress only for a first achievement, if more of them are sharing same data
}
else if ( AchDefs[AchIndex].bForceShow ) {
// achievement is already unlocked, but it is achieved again and author want to show it every time
AchDefs[AchIndex].bUnlockedJustNow = false;
ClientSetAchProgress(AchIndex, AchDefs[AchIndex].MaxProgress, false);
class'ScrnBalance'.default.Mut.AchievementEarned(self, AchIndex);
AnnounceEarn(self, AchIndex, false);
}
ProgressToWrite = max(ProgressToWrite, AchDefs[AchIndex].CurrentProgress);
AchIndex++;
} until ( AchIndex >= count || AchDefs[AchIndex].DataSize != DATA_USE_PREVIOUS );
WriteProgressToData(IndexToWrite, ProgressToWrite);
return result;
}
static final function bool ProgressAchievementByID(ClientPerkRepLink L, name ID, int Inc)
{
local SRCustomProgress S;
local ScrnAchievements A;
local int i;
if ( L == none || L.Level.Game.GameDifficulty < 2 )
return false;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
for ( i = 0; i < A.AchDefs.length; ++i ) {
if ( A.AchDefs[i].ID == ID )
return A.ProgressAchievement(i, Inc);
}
}
}
return false;
}
// override to handle achievement earning events
function AchievementEarned(ScrnAchievements A, int Index, bool bFirstTimeEarned) {}
static final private function AnnounceEarn(ScrnAchievements AchOwner, int AchIndex, bool bFirstTimeEarned)
{
local SRCustomProgress S;
local ScrnAchievements A;
for( S = AchOwner.RepLink.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none )
A.AchievementEarned(AchOwner, AchIndex, bFirstTimeEarned);
}
}
static final function bool ResetAchievementByID(ClientPerkRepLink L, name ID)
{
local SRCustomProgress S;
local ScrnAchievements A;
local int i;
if ( L == none || L.Level.Game.GameDifficulty < 2 )
return false;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
for ( i = 0; i < A.AchDefs.length; ++i ) {
if ( A.AchDefs[i].ID == ID ) {
A.ProgressAchievement(i, -A.AchDefs[i].CurrentProgress);
return true;
}
}
}
}
return false;
}
simulated function UpdateData()
{
super.UpdateData();
UpdateAchievements();
}
// add custom progress values for all AchDefs
static final function InitAchievements(ClientPerkRepLink L)
{
local int i;
if ( L == none )
return;
for ( i = 0; i < class'ScrnAchievements'.default.AchClassList.Length; ++i ) {
if ( class'ScrnAchievements'.default.AchClassList[i] != none )
L.AddCustomValue(class'ScrnAchievements'.default.AchClassList[i]);
}
}
// use this function to add custom achievements to the list
static final function RegisterAchievements( class<ScrnAchievements> NewAchClass )
{
local int i;
for ( i = 0; i < class'ScrnAchievements'.default.AchClassList.Length; ++i ) {
if ( class'ScrnAchievements'.default.AchClassList[i] == NewAchClass )
return;
}
class'ScrnAchievements'.default.AchClassList[i] = NewAchClass;
}
static final function UnRegisterAchievements( class<ScrnAchievements> AchClass )
{
local int i;
for ( i = 0; i < class'ScrnAchievements'.default.AchClassList.Length; ++i ) {
if ( class'ScrnAchievements'.default.AchClassList[i] == AchClass ) {
class'ScrnAchievements'.default.AchClassList.remove(i, 1);
return;
}
}
}
static final function ResetAchList()
{
class'ScrnAchievements'.default.AchClassList.Length = 2;
class'ScrnAchievements'.default.AchClassList[0] = Class'ScrnBalanceSrv.Ach';
class'ScrnAchievements'.default.AchClassList[1] = Class'ScrnBalanceSrv.AchMaps';
}
simulated function GetAchievementStats(out int Completed, out int Total, optional int AchievementFlags, optional name Group)
{
local int i, count;
Completed = 0;
Total = 0;
count = GetAchievementCount();
for ( i = 0; i < count; ++i ) {
if ( (Group == '' || Group == AchDefs[i].Group) && FilterMached(AchievementFlags, AchDefs[i].FilterMaskAll, AchDefs[i].FilterMaskAny) ) {
Total++;
if ( AchDefs[i].CurrentProgress >= AchDefs[i].MaxProgress )
Completed++;
}
}
}
static final function GetGlobalAchievementStats(ClientPerkRepLink L, out int Completed, out int Total, optional int AchievementFlags, optional name Group)
{
local SRCustomProgress S;
local ScrnAchievements A;
local int c, t;
Completed = 0;
Total = 0;
if ( L == none )
return;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
A.GetAchievementStats(c, t, AchievementFlags, Group);
Completed += c;
Total += t;
}
}
}
simulated function string GetDisplayString()
{
local int Completed, Total;
GetAchievementStats(Completed, Total);
return Completed $ " / " $ Total;
}
//returns true if Flags matched both FilterAll and FilterAny, or their values are 0
static function bool FilterMached(int Flags, int FilterMaskAll, int FilterMaskAny)
{
return Flags == 0 || (
(FilterMaskAll == 0 || (FilterMaskAll & Flags) == FilterMaskAll)
&& (FilterMaskAny == 0 || (FilterMaskAny & Flags) != 0) ); //this reminding me LISP ;)
}
simulated function int GetVisibleAchCount()
{
return VisibleAchCount;
}
// returns real achievement index (which can be used to access AchDefs) by visible index
// uses bDisplayFlag
// returns -1 if visible index is you of bounds
simulated function int GetVisibleAchIndex(int VisibleIndex)
{
local int i;
if ( VisibleAchCount < 0 )
return -1;
for ( i=0; i < AchDefs.Length; ++i ) {
if ( AchDefs[i].bDisplayFlag ) {
if (VisibleIndex == 0)
return i;
else
VisibleIndex--;
}
}
return -1;
}
// sets bDisplayFlag of AchDefs
simulated function SetVisibility(optional int AchievementFlags, optional name Group, optional bool bOnlyLocked)
{
local int i;
VisibleAchCount = 0;
for ( i = 0; i < AchDefs.length; ++i ) {
AchDefs[i].bDisplayFlag = (!bOnlyLocked || !IsUnlocked(i) )
&& (Group == '' || Group == AchDefs[i].Group)
&& FilterMached(AchievementFlags, AchDefs[i].FilterMaskAll, AchDefs[i].FilterMaskAny);
if ( AchDefs[i].bDisplayFlag )
VisibleAchCount++;
// else
// log("Achievement "$AchDefs[i].ID $ " didn't pass filter " $ IntToHex(AchievementFlags), 'ScrnBalance');
}
}
static final function AchStrInfo GetAchievementByID(ClientPerkRepLink L, name ID, optional bool bOnlyLocked )
{
local SRCustomProgress S;
local ScrnAchievements A;
local int i;
local AchStrInfo result;
if ( L == none )
return result;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
for ( i = 0; i < A.AchDefs.length; ++i ) {
if ( A.AchDefs[i].ID == ID ) {
if ( !bOnlyLocked || !A.IsUnlocked(i) ) {
result.AchHandler = A;
result.AchIndex = i;
}
return result;
}
}
}
}
return result;
}
// returns true if achievement with a given ID is unlocked
// returns false if achievement is locked or doesn't exist
static final function bool IsAchievementUnlocked(ClientPerkRepLink L, name ID)
{
local AchStrInfo A;
A = GetAchievementByID(L, ID, false);
if ( A.AchHandler == none )
return false;
return A.AchHandler.IsUnlocked(A.AchIndex);
}
// sets list of all achievement handlers with bDisplayFlag set
// returns visible achievement count
static final function int GetAllAchievements(ClientPerkRepLink L, out array<ScrnAchievements> AchHandlers,
optional int AchievementFlags, optional name Group, optional bool bOnlyLocked )
{
local SRCustomProgress S;
local ScrnAchievements A;
local int count;
AchHandlers.Length = 0;
if ( L == none )
return 0;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
AchHandlers[AchHandlers.Length] = A;
A.SetVisibility(AchievementFlags, Group, bOnlyLocked);
count += A.VisibleAchCount;
}
}
return count;
}
static final function ResetAchievements(ClientPerkRepLink L, name Group)
{
local SRCustomProgress S;
local ScrnAchievements A;
local int i;
if ( L == none )
return;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
for ( i = 0; i < A.AchDefs.length; ++i ) {
if ( Group == A.AchDefs[i].Group ) {
A.AchDefs[i].CurrentProgress = 0;
A.WriteProgressToData(i, 0);
}
}
}
}
}
simulated function texture GetIcon(int AchIndex)
{
if ( AchDefs[AchIndex].CurrentProgress >= AchDefs[AchIndex].MaxProgress )
return AchDefs[AchIndex].Icon;
return LockedIcon;
}
simulated function bool IsUnlocked(int AchIndex)
{
return AchDefs[AchIndex].CurrentProgress >= AchDefs[AchIndex].MaxProgress;
}
static final function RetrieveGroups(ClientPerkRepLink L, out array<name> GroupNames, out array<string> GroupCaptions)
{
local SRCustomProgress S;
local ScrnAchievements A;
local int i, j;
local bool bFound;
if ( L == none )
return;
if ( GroupNames.length != GroupCaptions.length )
GroupCaptions.length = GroupNames.length;
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
for ( i = 0; i < A.GroupInfo.length; ++i ) {
bFound = false;
for ( j = 0; j < GroupNames.length; ++j ) {
if ( A.GroupInfo[i].Group == GroupNames[j] ) {
bFound = true;
break;
}
}
if ( !bFound ) {
j = GroupNames.length;
GroupNames[j] = A.GroupInfo[i].Group;
GroupCaptions[j] = A.GroupInfo[i].Caption;
}
}
}
}
}
simulated function string LocalGroupCaption(ClientPerkRepLink L, name GroupName)
{
local int i;
for ( i = 0; i < GroupInfo.length; ++i ) {
if ( GroupInfo[i].Group == GroupName )
return GroupInfo[i].Caption;
}
return "";
}
static final function string GroupCaption(ClientPerkRepLink L, name GroupName)
{
local SRCustomProgress S;
local ScrnAchievements A;
local string result;
if ( L != none ) {
for( S = L.CustomLink; S != none; S = S.NextLink ) {
A = ScrnAchievements(S);
if( A != none ) {
result = A.LocalGroupCaption(L, GroupName);
if ( result != "" )
return result;
}
}
}
return string(GroupName);
}
simulated function ClientPerkRepLink GetRepLink()
{
if ( RepLink == none && Level.NetMode == NM_Client )
RepLink = Class'ScrnClientPerkRepLink'.Static.FindMe(Level.GetLocalPlayerController());
return RepLink;
}
defaultproperties
{
LockedIcon=Texture'KillingFloorHUD.Achievements.KF_Achievement_Lock'
AchClassList(0)=Class'ScrnBalanceSrv.Ach'
AchClassList(1)=Class'ScrnBalanceSrv.AchMaps'
GroupInfo(0)=(Caption="ALL")
bNeedToSetDefaultAchievementData=True
bFixedDataSize=True
bReplicateDataToClients=True
}

View file

@ -0,0 +1,196 @@
class ScrnAchievementsList extends GUIVertList;
// Settings
var() float OuterBorder;
var() float ItemBorder;
var() float TextTopOffset;
var() float ItemSpacing;
var() float IconToNameSpacing;
var() float NameToDescriptionSpacing;
var() float ProgressBarWidth;
var() float ProgressBarHeight;
var() float ProgressTextSpacing;
var() float TextHeight, TextWidth;
// Display
var texture ItemBackground;
var texture ProgressBarBackground;
var texture ProgressBarForeground;
// State
var ClientPerkRepLink MyClientPerkRepLink;
var array<ScrnAchievements> AchievementHandlers;
function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
OnDrawItem = DrawAchievement;
Super.InitComponent(MyController, MyOwner);
}
function Closed(GUIComponent Sender, bool bCancelled)
{
MyClientPerkRepLink = none;
super.Closed(Sender, bCancelled);
}
function InitList(ClientPerkRepLink L, optional name GroupName, optional bool bOnlyLocked)
{
//log("ScrnAchievementsList.InitList", 'ScrnBalance');
// Hold onto our reference
MyClientPerkRepLink = L;
// Update the ItemCount and select the first item
ItemCount = class'ScrnBalanceSrv.ScrnAchievements'.static.GetAllAchievements(
L, AchievementHandlers, class'ScrnBalance'.default.Mut.AchievementFlags
,GroupName, bOnlyLocked);
SetIndex(0);
if ( bNotify )
{
CheckLinkedObjects(Self);
}
if ( MyScrollBar != none )
{
MyScrollBar.AlignThumb();
}
}
// returns AchHandler and AchIndex of the given ListIndex
function bool ListIndexToAch(int ListIndex, out ScrnAchievements AchHandler, out int AchIndex)
{
local int i, vCount;
for ( i=0; i < AchievementHandlers.Length; ++i ) {
vCount = AchievementHandlers[i].GetVisibleAchCount();
if ( ListIndex < vCount ) {
AchIndex = AchievementHandlers[i].GetVisibleAchIndex(ListIndex);
if ( AchIndex == -1 )
return false;
AchHandler = AchievementHandlers[i];
return true;
}
else
ListIndex -= vCount;
}
}
function DrawAchievement(Canvas Canvas, int Index, float X, float Y, float Width, float Height, bool bSelected, bool bPending)
{
local float TempX, TempY, BarX, BarY;
//local float OrgX, ClipX, ClipY;
local float IconSize;
local string ProgressString;
local eMenuState TextStyle;
local ScrnAchievements AchHandler;
local int AchIndex;
// Offset for the Background
TempX = X + OuterBorder * Width;
TempY = Y + ItemSpacing / 2.0;
// Initialize the Canvas
Canvas.Style = 1;
// Draw Item Background
Canvas.SetDrawColor(255, 255, 255, 192);
Canvas.SetPos(TempX, TempY);
Canvas.DrawTileStretched(ItemBackground, Width - (OuterBorder * Width * 2.0), Height - ItemSpacing);
if ( !ListIndexToAch(Index, AchHandler, AchIndex) )
return; //wtf?
if ( AchHandler.IsUnlocked(AchIndex) ) {
Canvas.SetDrawColor(255, 255, 255, 255);
TextStyle = MSAT_Blurry;
}
else {
Canvas.SetDrawColor(127, 127, 127, 255);
TextStyle = MSAT_Disabled;
}
// Offset and Calculate Icon's Size
TempX += ItemBorder * Height;
TempY += ItemBorder * Height;
IconSize = Height - ItemSpacing - (ItemBorder * Height * 2.0);
// Draw Icon
Canvas.SetPos(TempX, TempY);
Canvas.DrawTile(AchHandler.GetIcon(AchIndex), IconSize, IconSize, 0, 0, 64, 64);
TempX += IconSize + IconToNameSpacing * Width;
TempY += TextTopOffset * Height;
BarY = TempY;
//Draw the Display Name
SectionStyle.DrawText(Canvas, TextStyle, TempX, TempY, Width * TextWidth, TextHeight * Height, TXTA_Left, AchHandler.AchDefs[AchIndex].DisplayName, FNS_Medium);
//Draw the Description
TempY += (TextHeight + NameToDescriptionSpacing) * Height;
SectionStyle.DrawText(Canvas, TextStyle, TempX, TempY, Width * TextWidth, Height*0.5, TXTA_Left,
AchHandler.AchDefs[AchIndex].Description, FNS_Small);
// OrgX = Canvas.OrgX;
// ClipX = Canvas.ClipX;
// ClipY = Canvas.ClipY;
// Canvas.SetPos(TempX, TempY);
// Canvas.OrgX = TempX;
// Canvas.ClipX = Width - OuterBorder * Width;
// Canvas.ClipY = Height - (Y + ItemSpacing*2.0);
// Canvas.DrawText( AchHandler.AchDefs[AchIndex].Description);
// Canvas.OrgX = OrgX;
// Canvas.ClipX = ClipX;
// Canvas.ClipY = ClipY;
if ( AchHandler.AchDefs[AchIndex].MaxProgress > 1 && !AchHandler.IsUnlocked(AchIndex) ) {
// Show progress
BarX = X + Width - (OuterBorder * Width) - (ItemBorder * Height * 2.0) - (ProgressBarWidth * Width);
// Draw Progress Bar
Canvas.SetPos(BarX, BarY);
Canvas.DrawTileStretched(ProgressBarBackground, ProgressBarWidth * Width, ProgressBarHeight * Height);
Canvas.SetPos(BarX + 3.0, BarY + 3.0);
if ( AchHandler.AchDefs[AchIndex].CurrentProgress < AchHandler.AchDefs[AchIndex].MaxProgress )
{
Canvas.DrawTileStretched(ProgressBarForeground, ((ProgressBarWidth * Width) - 6.0) * (float(AchHandler.AchDefs[AchIndex].CurrentProgress) / float(AchHandler.AchDefs[AchIndex].MaxProgress)), ProgressBarHeight * Height - 6.0);
}
else
{
Canvas.DrawTileStretched(ProgressBarForeground, ProgressBarWidth * Width - 6.0, ProgressBarHeight * Height - 6.0);
}
// Draw Progress Text
ProgressString = AchHandler.AchDefs[AchIndex].CurrentProgress $"/"$ AchHandler.AchDefs[AchIndex].MaxProgress;
//SectionStyle.DrawText(Canvas, MSAT_Blurry, BarX - 150 - (ProgressTextSpacing * Width), BarY, 150, (TextHeight * Height), TXTA_Right, ProgressString, FNS_Medium);
SectionStyle.DrawText(Canvas, MSAT_Blurry, BarX, BarY, ProgressBarWidth * Width, (ProgressBarHeight * Height), TXTA_Center, ProgressString, FNS_Medium);
}
}
function float AchievementHeight(Canvas c)
{
return (MenuOwner.ActualHeight() / 8.0) - 1.0;
}
defaultproperties
{
OuterBorder=0.015000
ItemBorder=0.050000
TextTopOffset=0.082000
ItemSpacing=3.000000
IconToNameSpacing=0.018000
NameToDescriptionSpacing=0.040000
ProgressBarWidth=0.227000
ProgressBarHeight=0.350000
ProgressTextSpacing=0.009000
TextHeight=0.300000
TextWidth=0.850000
ItemBackground=Texture'KF_InterfaceArt_tex.Menu.Thin_border_SlightTransparent'
ProgressBarBackground=Texture'KF_InterfaceArt_tex.Menu.Innerborder'
ProgressBarForeground=Texture'InterfaceArt_tex.Menu.progress_bar'
GetItemHeight=ScrnAchievementsList.AchievementHeight
FontScale=FNS_Medium
}

View file

@ -0,0 +1,31 @@
class ScrnAchievementsListBox extends GUIListBoxBase;
var ScrnAchievementsList List;
function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
Super.InitComponent(MyController,MyOwner);
if ( DefaultListClass != "" )
{
List = ScrnAchievementsList(AddComponent(DefaultListClass));
if ( List == none )
{
log(Class$".InitComponent - Could not create default list ["$DefaultListClass$"]");
return;
}
}
if ( List == none )
{
Warn("Could not initialize list!");
return;
}
InitBaseList(List);
}
defaultproperties
{
DefaultListClass="ScrnBalanceSrv.ScrnAchievementsList"
}

View file

@ -0,0 +1,184 @@
class ScrnAmmoPickup extends KFAmmoPickup;
function float GetRespawnTime()
{
return RespawnTime / clamp(Level.Game.NumPlayers, 1, 6);
}
state Pickup
{
function BeginState()
{
super.BeginState();
if ( ScrnGameType(Level.Game) != none )
ScrnGameType(Level.Game).CurrentAmmoBoxCount++;
}
function EndState()
{
super.EndState();
if ( ScrnGameType(Level.Game) != none )
ScrnGameType(Level.Game).CurrentAmmoBoxCount--;
}
// When touched by an actor.
function Touch(Actor Other)
{
local Inventory CurInv;
local bool bPickedUp;
local int AmmoPickupAmount;
local Boomstick DBShotty;
local bool bResuppliedBoomstick;
local KFAmmunition ammo;
local KFPlayerReplicationInfo KFPRI;
if ( Pawn(Other) != none && Pawn(Other).bCanPickupInventory && Pawn(Other).Controller != none &&
FastTrace(Other.Location, Location) )
{
KFPRI = KFPlayerReplicationInfo(Pawn(Other).PlayerReplicationInfo);
for ( CurInv = Other.Inventory; CurInv != none; CurInv = CurInv.Inventory )
{
if( Boomstick(CurInv) != none )
{
DBShotty = Boomstick(CurInv);
}
ammo = KFAmmunition(CurInv);
if ( ammo != none && ammo.bAcceptsAmmoPickups )
{
// changed from 1 to 0 -- PooSH
if ( ammo.AmmoPickupAmount > 0 )
{
if ( ammo.AmmoAmount < ammo.MaxAmmo )
{
if ( KFPRI != none && KFPRI.ClientVeteranSkill != none )
{
AmmoPickupAmount = float(ammo.AmmoPickupAmount) * KFPRI.ClientVeteranSkill.static.GetAmmoPickupMod(KFPRI, ammo);
}
else
{
AmmoPickupAmount = ammo.AmmoPickupAmount;
}
ammo.AmmoAmount = Min(ammo.MaxAmmo, ammo.AmmoAmount + AmmoPickupAmount);
if( DBShotgunAmmo(CurInv) != none )
{
bResuppliedBoomstick = true;
}
bPickedUp = true;
}
}
else if ( ammo.AmmoAmount < ammo.MaxAmmo )
{
bPickedUp = true;
if ( FRand() <= (1.0 / Level.Game.GameDifficulty) )
{
ammo.AmmoAmount++;
}
}
}
}
if ( bPickedUp )
{
// TODO: test if this KF hack is still needed in ScrN
// if( bResuppliedBoomstick && DBShotty != none )
// {
// DBShotty.AmmoPickedUp();
// }
AnnouncePickup(Pawn(Other));
GotoState('Sleeping', 'Begin');
if ( KFGameType(Level.Game) != none )
{
KFGameType(Level.Game).AmmoPickedUp(self);
}
}
}
}
}
auto state Sleeping
{
ignores Touch;
function bool ReadyToPickup(float MaxWait)
{
return (bPredictRespawns && LatentFloat < MaxWait);
}
function StartSleeping() {}
function BeginState()
{
local int i;
NetUpdateTime = Level.TimeSeconds - 1;
bHidden = true;
bSleeping = true;
SetCollision(false, false);
for ( i = 0; i < 4; i++ )
{
TeamOwner[i] = None;
}
}
function EndState()
{
NetUpdateTime = Level.TimeSeconds - 1;
bHidden = false;
bSleeping = false;
SetCollision(default.bCollideActors, default.bBlockActors);
}
Begin:
bSleeping = true;
Sleep(1000000.0); // Sleep for 11.5 days(never wake up)
DelayedSpawn:
bSleeping = false;
Sleep(GetRespawnTime()); // Delay before respawning
goto('Respawn');
TryToRespawnAgain:
Sleep(1.0);
Respawn:
bShowPickup = true;
// ignore player visibility here -- PooSH
// for ( OtherPlayer = Level.ControllerList; OtherPlayer != none; OtherPlayer=OtherPlayer.NextController )
// {
// if ( PlayerController(OtherPlayer) != none && OtherPlayer.Pawn != none )
// {
// if ( FastTrace(self.Location, OtherPlayer.Pawn.Location) )
// {
// bShowPickup = false;
// break;
// }
// }
// }
if ( bShowPickup )
{
RespawnEffect();
Sleep(RespawnEffectTime);
if ( PickUpBase != none )
{
PickUpBase.TurnOn();
}
GotoState('Pickup');
}
else
Goto('TryToRespawnAgain');
}
defaultproperties
{
RotationRate=(Yaw=0)
}

View file

@ -0,0 +1,10 @@
class ScrnAxe extends Axe;
defaultproperties
{
bIsTier2Weapon=False
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnAxeFire'
FireModeClass(1)=Class'ScrnBalanceSrv.ScrnAxeFireB'
PickupClass=Class'ScrnBalanceSrv.ScrnAxePickup'
ItemName="Axe SE"
}

View file

@ -0,0 +1,7 @@
class ScrnAxeFire extends AxeFire;
defaultproperties
{
WideDamageMinHitAngle=0.750000
bWaitForRelease=True
}

View file

@ -0,0 +1,7 @@
class ScrnAxeFireB extends AxeFireB;
defaultproperties
{
WideDamageMinHitAngle=0.000000
bWaitForRelease=True
}

View file

@ -0,0 +1,9 @@
class ScrnAxePickup extends AxePickup;
defaultproperties
{
cost=200
ItemName="Axe SE"
ItemShortName="Axe SE"
InventoryType=Class'ScrnBalanceSrv.ScrnAxe'
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
class ScrnBalancePersistence extends Object
Config(ScrnInternal);
var config byte Difficulty;
defaultproperties
{
}

View file

@ -0,0 +1,931 @@
class ScrnBalanceVoting extends ScrnVotingOptions;
var ScrnBalance Mut;
const VOTE_PERKLOCK = 0;
const VOTE_PERKUNLOCK = 1;
const VOTE_PAUSE = 2;
const VOTE_ENDTRADE = 3;
const VOTE_BLAME = 4;
const VOTE_KICK = 5;
const VOTE_BORING = 6;
const VOTE_SPAWN = 7;
const VOTE_ENDWAVE = 8;
const VOTE_SPEC = 9;
const VOTE_READY = 10;
const VOTE_UNREADY = 11;
const VOTE_TEAMLOCK = 12;
const VOTE_TEAMUNLOCK = 13;
const VOTE_INVITE = 14;
const VOTE_FF = 15;
const VOTE_MAPRESTART = 16;
const VOTE_FAKEDPLAYERS = 17;
const VOTE_FAKEDCOUNT = 18;
const VOTE_FAKEDHEALTH = 19;
const VOTE_DIFF = 20;
const VOTE_RKILL = 100;
var localized string strCantEndTrade;
var localized string strTooLate;
var localized string strGamePaused, strSecondsLeft, strGameUnPaused, strPauseTraderOnly;
var localized string viResume, viEndTrade, viDifficulty;
var localized string strZedSpawnsDoubled;
var localized string strSquadNotFound, strCantSpawnSquadNow, strSquadList;
var localized string strNotInStoryMode, strNotInTSC;
var localized string strCantEndWaveNow, strEndWavePenalty;
var localized string strRCommands;
//variables for GamePaused state
var int PauseTime;
var transient bool bPauseable;
var transient string msgPause;
var string Reason; // reason why voting was started (e.g. kick player for being noob)
var transient float LastBlameVoteTime;
function class<ScrnVeterancyTypes> FindPerkByName(PlayerController Sender, string VeterancyNameOrIndex)
{
local int i;
local ClientPerkRepLink L;
local class<ScrnVeterancyTypes> Perk;
local string s1, s2;
// log("FindPerkByName("$Sender$", "$VeterancyNameOrIndex$")", 'ScrnBalance');
if ( Sender == none || VeterancyNameOrIndex == "" || SRStatsBase(Sender.SteamStatsAndAchievements) == none )
return none;
L = SRStatsBase(Sender.SteamStatsAndAchievements).Rep;
if ( L == none )
return none;
i = int(VeterancyNameOrIndex);
if ( i > 0 && i <= L.CachePerks.Length )
return class<ScrnVeterancyTypes>(L.CachePerks[i-1].PerkClass);
// log("CachePerks.Length="$L.CachePerks.Length, 'ScrnBalance');
for ( i = 0; i < L.CachePerks.Length; ++i ) {
Perk = class<ScrnVeterancyTypes>(L.CachePerks[i].PerkClass);
if ( Perk != none ) {
// log(GetItemName(String(Perk.class)) @ Perk.default.VeterancyNameOrIndex, 'ScrnBalance');
if ( GetItemName(String(Perk.class)) ~= VeterancyNameOrIndex || Perk.default.VeterancyName ~= VeterancyNameOrIndex
|| (Divide(Perk.default.VeterancyName, " ", s1, s2) && (VeterancyNameOrIndex ~= s1 || VeterancyNameOrIndex ~= s2)) )
return Perk;
}
}
return none;
}
function SendSquadList(PlayerController Sender)
{
local int i;
local string s;
if ( Mut.Squads.Length == 0 ) {
Sender.ClientMessage(strOptionDisabled);
return;
}
s = strSquadList @ Mut.Squads[0].SquadName;
for ( i=1; i<Mut.Squads.Length; ++i ) {
s = s $ ", " $ Mut.Squads[i].SquadName;
}
Sender.ClientMessage(s);
}
static function bool TryStrToInt(string str, out int val)
{
val = int(str);
return val != 0 || str == "0";
}
function int GetVoteIndex(PlayerController Sender, string Key, out string Value, out string VoteInfo)
{
local int result, v;
local class<ScrnVeterancyTypes> Perk;
if ( Key == "LOCKPERK" ) {
if ( !Mut.bAllowLockPerkVote ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
Perk = FindPerkByName(Sender, Value);
if ( Perk == none )
return VOTE_ILLEGAL;
if ( Perk.default.bLocked )
return VOTE_NOEFECT;
result = VOTE_PERKLOCK;
Value = Perk.default.VeterancyName;
}
else if ( Key == "UNLOCKPERK" ) {
Perk = FindPerkByName(Sender, Value);
if ( Perk == none )
return VOTE_ILLEGAL;
if ( !Perk.default.bLocked )
return VOTE_NOEFECT;
result = VOTE_PERKUNLOCK;
Value = Perk.default.VeterancyName;
}
else if ( Key == "PAUSE" || (Level.Pauser != none && Key == "RESUME") ) {
if ( !Mut.bAllowPauseVote ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
if ( Mut.bPauseTraderOnly && !Mut.KF.bTradingDoorsOpen && Mut.KF.IsInState('MatchInProgress') ) {
Sender.ClientMessage(strPauseTraderOnly);
return VOTE_NOEFECT;
}
result = VOTE_PAUSE;
if ( Value == "" )
Value = "60";
else {
v = int(Value);
if ( v <= 0 )
v = 60;
Value = string(v);
}
if ( Level.Pauser != none )
VoteInfo = viResume;
}
else if ( Key == "ENDTRADE" || (Key == "END" && Value == "TRADE") ) {
if ( Mut.bStoryMode ) {
Sender.ClientMessage(strNotInStoryMode);
return VOTE_NOEFECT;
}
if ( Mut.KF.bWaveInProgress|| Mut.KF.WaveCountDown < 10 || Mut.SkippedTradeTimeMult < 0 ) {
Sender.ClientMessage(strCantEndTrade);
return VOTE_NOEFECT;
}
result = VOTE_ENDTRADE;
Value = "";
VoteInfo = viEndTrade;
}
else if ( Key == "BLAME" ) {
if ( !Mut.bAllowBlameVote ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
if ( Level.TimeSeconds - LastBlameVoteTime < Mut.BlameVoteCoolDown ) {
Sender.ClientMessage(strNotAvaliableATM);
return VOTE_LOCAL;
}
if ( Value == "" ) {
SendPlayerList(Sender);
return VOTE_LOCAL;
}
Reason = "";
if ( Left(Value, 1) == "\"" ) {
// don't look for player in quoted string - just blame it :)
VotingHandler.VotedPlayer = none;
Value = Mid(Value, 1);
Divide(Value, "\"", Value, Reason);
VotingHandler.VotedPlayer = none;
}
else {
Divide(Value, " ", Value, Reason);
if ( Value ~= "ALL" || Value ~= "TEAM" ) {
Value = "TEAM";
VoteInfo = "Blame Team";
VotingHandler.VotedPlayer = none;
}
else {
if ( Value ~= "ME" )
VotingHandler.VotedPlayer = Sender;
else
VotingHandler.VotedPlayer = FindPlayer(Value);
if ( VotingHandler.VotedPlayer == none ) {
Sender.ClientMessage(strPlayerNotFound);
SendPlayerList(Sender);
return VOTE_ILLEGAL;
}
Value = Mut.ColoredPlayerName(VotingHandler.VotedPlayer.PlayerReplicationInfo);
VoteInfo = "Blame " $ Value;
}
}
LastBlameVoteTime = Level.TimeSeconds;
result = VOTE_BLAME;
}
else if ( Key == "SPEC" ) {
if ( Level.Game.AccessControl == none
|| Level.Game.NumSpectators > Level.Game.MaxSpectators
|| (!Mut.bAllowKickVote && !Sender.PlayerReplicationInfo.bAdmin) )
{
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
if ( Value == "" ) {
SendPlayerList(Sender);
return VOTE_LOCAL;
}
Reason = "";
Divide(Value, " ", Value, Reason);
VotingHandler.VotedPlayer = FindPlayer(Value);
if ( VotingHandler.VotedPlayer == none ) {
Sender.ClientMessage(strPlayerNotFound);
SendPlayerList(Sender);
return VOTE_ILLEGAL;
}
Value = Mut.ColoredPlayerName(VotingHandler.VotedPlayer.PlayerReplicationInfo);
VoteInfo = "Spectate " $ Value;
result = VOTE_SPEC;
}
else if ( Key == "KICK" ) {
if ( Level.Game.AccessControl == none || (!Mut.bAllowKickVote && !Sender.PlayerReplicationInfo.bAdmin) ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
if ( Value == "" ) {
SendPlayerList(Sender);
return VOTE_LOCAL;
}
Reason = "";
Divide(Value, " ", Value, Reason);
VotingHandler.VotedPlayer = FindPlayer(Value);
if ( VotingHandler.VotedPlayer == none ) {
Sender.ClientMessage(strPlayerNotFound);
SendPlayerList(Sender);
return VOTE_ILLEGAL;
}
Value = Mut.ColoredPlayerName(VotingHandler.VotedPlayer.PlayerReplicationInfo);
VoteInfo = "Kick " $ Value;
result = VOTE_KICK;
}
else if ( Key == "INVITE" ) {
if ( !Mut.CheckScrnGT(Sender) )
return VOTE_LOCAL;
if ( Value == "" ) {
SendPlayerList(Sender);
return VOTE_LOCAL;
}
Reason = "";
Divide(Value, " ", Value, Reason);
VotingHandler.VotedPlayer = FindPlayer(Value);
if ( VotingHandler.VotedPlayer == none ) {
Sender.ClientMessage(strPlayerNotFound);
SendPlayerList(Sender);
return VOTE_ILLEGAL;
}
else if ( Mut.ScrnGT.IsInvited(VotingHandler.VotedPlayer) ) {
VotingHandler.VotedPlayer = none;
return VOTE_NOEFECT;
}
Value = Mut.ColoredPlayerName(VotingHandler.VotedPlayer.PlayerReplicationInfo);
VoteInfo = "Invite " $ Value;
result = VOTE_INVITE;
}
else if ( Key == "BORING" ) {
if ( Mut.bStoryMode ) {
Sender.ClientMessage(strNotInStoryMode);
return VOTE_LOCAL;
}
else if ( !Mut.bAllowBoringVote && !Sender.PlayerReplicationInfo.bAdmin ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_LOCAL;
}
else if ( Mut.KF.bTradingDoorsOpen || Mut.KF.KFLRules.WaveSpawnPeriod < 0.5 ) {
Sender.ClientMessage(strNotAvaliableATM);
return VOTE_LOCAL;
}
Value = "";
VoteInfo = "Game is BORING";
result = VOTE_BORING;
}
else if ( Key == "SPAWN" ) {
if ( Mut.bStoryMode && !Mut.bBeta ) {
Sender.ClientMessage(strNotInStoryMode);
return VOTE_NOEFECT;
}
if ( Mut.Squads.Length == 0 ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
if ( Value == "" ) {
SendSquadList(Sender);
return VOTE_LOCAL;
}
if ( Mut.FindSquad(Value) == -1 ) {
Sender.ClientMessage(strSquadNotFound);
return VOTE_ILLEGAL;
}
if ( Mut.KF.TotalMaxMonsters < 10 ) {
Sender.ClientMessage(strCantSpawnSquadNow);
return VOTE_NOEFECT;
}
result = VOTE_SPAWN;
}
else if ( Key == "ENDWAVE" || (Key == "END" && Value == "WAVE") ) {
VotingHandler.VotedTeam = Sender.PlayerReplicationInfo.Team;
if ( VotingHandler.VotedTeam == none )
return VOTE_ILLEGAL;
if ( Mut.KF.NumMonsters == 0 )
return VOTE_NOEFECT;
if ( Mut.MaxVoteKillMonsters == 0 ) {
Sender.ClientMessage(strOptionDisabled);
return VOTE_NOEFECT;
}
if ( Mut.KF.TotalMaxMonsters > 0 || Mut.KF.NumMonsters > Mut.MaxVoteKillMonsters
|| Mut.GameRules.bFinalWave || !CanEndWave() )
{
Sender.ClientMessage(strCantEndWaveNow);
return VOTE_NOEFECT;
}
return VOTE_ENDWAVE;
}
else if ( Key == "READY" ) {
if ( !Level.Game.bWaitingToStartMatch )
return VOTE_NOEFECT;
return VOTE_READY;
}
else if ( Key == "UNREADY" ) {
if ( !Level.Game.bWaitingToStartMatch )
return VOTE_NOEFECT;
return VOTE_UNREADY;
}
else if ( Key == "LOCKTEAM" || Key == "LOCKTEAMS" ) {
if ( !Mut.CheckScrnGT(Sender) )
return VOTE_LOCAL;
else if ( Mut.bTeamsLocked )
return VOTE_NOEFECT;
else if ( !Sender.PlayerReplicationInfo.bAdmin && (Mut.ScrnGT.WaveNum+1) < Mut.ScrnGT.RelativeWaveNum(Mut.LockTeamMinWave) ) {
Sender.ClientMessage(strNotAvaliableATM);
return VOTE_LOCAL;
}
return VOTE_TEAMLOCK;
}
else if ( Key == "UNLOCKTEAM" || Key == "UNLOCKTEAMS" ) {
if ( !Mut.CheckScrnGT(Sender) )
return VOTE_LOCAL;
else if ( !Mut.bTeamsLocked )
return VOTE_NOEFECT;
return VOTE_TEAMUNLOCK;
}
else if ( Key == "FF" ) {
if ( Mut.bTSCGame ) {
Sender.ClientMessage(strNotInTSC);
return VOTE_NOEFECT;
}
if ( Level.GRI.bMatchHasBegun ) {
Sender.ClientMessage(strNotAvaliableATM);
return VOTE_LOCAL;
}
if ( right(Value, 1) == "%" )
Value = left(Value, len(Value)-1);
if ( !TryStrToInt(Value, v) || v < Mut.MinVoteFF || v > Mut.MaxVoteFF )
return VOTE_ILLEGAL;
if ( v == int(Mut.KF.FriendlyFireScale*100) )
return VOTE_NOEFECT;
if ( v == 0 )
VoteInfo = "Friendly Fire OFF";
else
VoteInfo = "Friendly Fire "$v$"%";
return VOTE_FF;
}
else if ( Key == "MAP" && Value == "RESTART" ) {
result = VOTE_MAPRESTART;
}
else if ( Key == "FAKED" || Key == "FAKEDPLAYERS" ) {
if ( !Mut.CheckScrnGT(Sender) )
return VOTE_LOCAL;
if ( !TryStrToInt(Value, v) || v < 0 || v > 32 )
return VOTE_ILLEGAL;
if ( Mut.ScrnGT.ScrnGRI.FakedPlayers == v && Mut.ScrnGT.ScrnGRI.FakedAlivePlayers == v )
return VOTE_NOEFECT;
if ( v <= 1 )
VoteInfo = "Faked Players OFF";
else
VoteInfo = v $ " Faked Players";
return VOTE_FAKEDPLAYERS;
}
else if ( Key == "FAKEDCOUNT" ) {
if ( !Mut.CheckScrnGT(Sender) )
return VOTE_LOCAL;
if ( !TryStrToInt(Value, v) || v < 0 || v > 32 )
return VOTE_ILLEGAL;
if ( Mut.ScrnGT.ScrnGRI.FakedPlayers == v )
return VOTE_NOEFECT;
if ( v <= 1 )
VoteInfo = "Faked Zed Count OFF";
else
VoteInfo = v $ "p Faked Zed Count";
return VOTE_FAKEDCOUNT;
}
else if ( Key == "FAKEDHEALTH" ) {
if ( !Mut.CheckScrnGT(Sender) )
return VOTE_LOCAL;
if ( !TryStrToInt(Value, v) || v < 0 || v > 32 )
return VOTE_ILLEGAL;
if ( Mut.ScrnGT.ScrnGRI.FakedAlivePlayers == v )
return VOTE_NOEFECT;
if ( v <= 1 )
VoteInfo = "Faked Zed Health OFF";
else
VoteInfo = v $ "p Faked Zed Health";
return VOTE_FAKEDHEALTH;
}
else if ( Key == "DIFF" || Key == "DIFFICULTY" ) {
if ( Value == "" ) {
Sender.ClientMessage("Usage: MVOTE DIFF DEFAULT|NORMAL|HARD|SUI|SUI+|HOE|HOE+");
return VOTE_LOCAL;
}
v = GetDifficulty(Value);
if ( v != 0 && v < Mut.MinVoteDifficulty || v > 8 )
return VOTE_ILLEGAL;
if ( v == Mut.Persistence.Difficulty )
return VOTE_NOEFECT;
VoteInfo = Value @ viDifficulty;
Value = string(v);
return VOTE_DIFF;
}
else if ( Key == "R_KILL" ) {
if ( !Sender.PlayerReplicationInfo.bAdmin || Mut.SrvTourneyMode == 0 ) {
Sender.ClientMessage(strRCommands);
return VOTE_LOCAL;
}
if ( Value == "" ) {
SendPlayerList(Sender);
return VOTE_LOCAL;
}
Reason = "";
Divide(Value, " ", Value, Reason);
VotingHandler.VotedPlayer = FindPlayer(Value);
if ( VotingHandler.VotedPlayer == none ) {
Sender.ClientMessage(strPlayerNotFound);
SendPlayerList(Sender);
return VOTE_ILLEGAL;
}
Value = Mut.ColoredPlayerName(VotingHandler.VotedPlayer.PlayerReplicationInfo);
VoteInfo = "Referee KILL " $ Value;
result = VOTE_RKILL;
}
else
return VOTE_UNKNOWN;
return result;
}
function ApplyVoteValue(int VoteIndex, string VoteValue)
{
local class<ScrnVeterancyTypes> Perk;
local ScrnCustomPRI ScrnPRI;
switch ( VoteIndex ) {
case VOTE_PERKLOCK: case VOTE_PERKUNLOCK:
Perk = FindPerkByName(VotingHandler.VoteInitiator, VoteValue);
if ( Perk != none ) {
Mut.LockPerk(Perk, VoteIndex == VOTE_PERKLOCK);
}
break;
case VOTE_PAUSE:
if (Level.Pauser == none ) {
//pause game
if ( Mut.bPauseTraderOnly && !Mut.KF.bTradingDoorsOpen && Mut.KF.IsInState('MatchInProgress') ) {
VotingHandler.BroadcastMessage(strPauseTraderOnly);
return;
}
PauseTime = int(VoteValue);
if ( PauseTime <= 0 )
PauseTime = 60;
GotoState('GamePaused', 'Begin');
//Enable('Tick');
}
else {
//resume game
Level.Pauser = none;
VotingHandler.BroadcastMessage(strGameUnpaused);
//Disable('Tick');
}
break;
case VOTE_ENDTRADE:
if ( Mut.KF.bWaveInProgress || Mut.KF.WaveCountDown < 6 ) {
VotingHandler.BroadcastMessage(strTooLate);
return;
}
Mut.TradeTimeAddSeconds = max(float(Mut.KF.WaveCountDown - 5) * Mut.SkippedTradeTimeMult, 0);
Mut.KF.WaveCountDown = 6; // need to left at least 6 to execute kfgametype.timer() events
break;
case VOTE_BLAME:
if ( VotingHandler.VotedPlayer != none )
VoteValue = Mut.ColoredPlayerName(VotingHandler.VotedPlayer.PlayerReplicationInfo);
LastBlameVoteTime = Level.TimeSeconds;
if ( Reason == "" )
VotingHandler.BroadcastMessage(VoteValue $ " blamed");
else
VotingHandler.BroadcastMessage(VoteValue $ " blamed for " $Reason);
//achievement
if ( IsGoodReason(Reason) && VotingHandler.VoteInitiator != none
&& SRStatsBase(VotingHandler.VoteInitiator.SteamStatsAndAchievements) != none )
{
class'ScrnBalanceSrv.ScrnAchievements'.static.ProgressAchievementByID(
SRStatsBase(VotingHandler.VoteInitiator.SteamStatsAndAchievements).Rep, 'Blame55p', 1);
if ( VotingHandler.VotedPlayer == VotingHandler.VoteInitiator )
class'ScrnBalanceSrv.ScrnAchievements'.static.ProgressAchievementByID(
SRStatsBase(VotingHandler.VoteInitiator.SteamStatsAndAchievements).Rep, 'BlameMe', 1);
else if ( ScrnPlayerController(VotingHandler.VotedPlayer) != none && ScrnPlayerController(VotingHandler.VotedPlayer).BeggingForMoney >= 3 )
{
class'ScrnBalanceSrv.ScrnAchievements'.static.ProgressAchievementByID(
SRStatsBase(VotingHandler.VoteInitiator.SteamStatsAndAchievements).Rep, 'SellCrap', 1);
VotingHandler.VotedPlayer.ReceiveLocalizedMessage(class'ScrnBalanceSrv.ScrnFakedAchMsg', 1);
ScrnPlayerController(VotingHandler.VotedPlayer).BeggingForMoney = 0;
}
}
if ( VotingHandler.VotedPlayer != none ) {
ScrnPRI = class'ScrnCustomPRI'.static.FindMe(VotingHandler.VotedPlayer.PlayerReplicationInfo);
if ( ScrnPRI != none ) {
VotingHandler.VotedPlayer.ReceiveLocalizedMessage(class'ScrnBalanceSrv.ScrnBlamedMsg', ScrnPRI.BlameCounter++); // more blame = bigger shit
//achievement
if ( ScrnPRI.BlameCounter == 5
&& SRStatsBase(VotingHandler.VotedPlayer.SteamStatsAndAchievements) != none )
class'ScrnBalanceSrv.ScrnAchievements'.static.ProgressAchievementByID(
SRStatsBase(VotingHandler.VotedPlayer.SteamStatsAndAchievements).Rep, 'MaxBlame', 1);
}
else
VotingHandler.VotedPlayer.ReceiveLocalizedMessage(class'ScrnBalanceSrv.ScrnBlamedMsg');
}
if ( VoteValue ~= "TEAM" || VoteValue ~= "ALL" ) {
BlameAll();
//achievement
if ( IsGoodReason(Reason) && VotingHandler.VoteInitiator != none
&& SRStatsBase(VotingHandler.VoteInitiator.SteamStatsAndAchievements) != none )
class'ScrnBalanceSrv.ScrnAchievements'.static.ProgressAchievementByID(
SRStatsBase(VotingHandler.VoteInitiator.SteamStatsAndAchievements).Rep, 'BlameTeam', 1);
}
else if ( VoteValue ~= "Baron" || (VotingHandler.VotedPlayer != none && VotingHandler.VotedPlayer.GetPlayerIDHash() == "76561198006289592") ) {
Mut.BroadcastFakedAchievement(0); // blame Baron :)
// blame the one who blamed baron
if ( VotingHandler.VoteInitiator != none && VotingHandler.VotedPlayer != VotingHandler.VoteInitiator ) {
VotingHandler.VotedPlayer = VotingHandler.VoteInitiator;
Reason = "Blaming Baron";
ApplyVoteValue(VoteIndex, VoteValue);
}
}
else if ( VoteValue ~= "TWI" || VoteValue ~= "Tripwire" ) {
Mut.BroadcastFakedAchievement(3); // blame Tripwire :)
}
else
BlameMonster(VoteValue);
break;
case VOTE_SPEC:
if ( VotingHandler.VotedPlayer != none && !VotingHandler.VotedPlayer.PlayerReplicationInfo.bAdmin ) {
if ( Mut.ScrnGT != none )
Mut.ScrnGT.UninvitePlayer(VotingHandler.VotedPlayer);
VotingHandler.VotedPlayer.BecomeSpectator();
}
break;
case VOTE_KICK:
if ( VotingHandler.VotedPlayer != none && !VotingHandler.VotedPlayer.PlayerReplicationInfo.bAdmin && NetConnection(VotingHandler.VotedPlayer.Player)!=None ) {
if ( Mut.ScrnGT != none )
Mut.ScrnGT.UninvitePlayer(VotingHandler.VotedPlayer);
if ( Reason == "" ) {
VotingHandler.BroadcastMessage(VoteValue $ " kicked");
VotingHandler.VotedPlayer.ClientNetworkMessage("AC_Kicked", "Team Vote");
}
else {
VotingHandler.BroadcastMessage(VoteValue $ " kicked for " $Reason);
VotingHandler.VotedPlayer.ClientNetworkMessage("AC_Kicked", Reason);
}
if (VotingHandler.VotedPlayer.Pawn != none && Vehicle(VotingHandler.VotedPlayer.Pawn) == none)
VotingHandler.VotedPlayer.Pawn.Destroy();
if (VotingHandler.VotedPlayer != None)
VotingHandler.VotedPlayer.Destroy();
}
break;
case VOTE_BORING:
Mut.KF.KFLRules.WaveSpawnPeriod *= 0.5;
VotingHandler.BroadcastMessage(strZedSpawnsDoubled $ " ("$Mut.KF.KFLRules.WaveSpawnPeriod$")");
break;
case VOTE_SPAWN:
Mut.SpawnSquad(VoteValue);
break;
case VOTE_ENDWAVE:
if ( Mut.KF.TotalMaxMonsters > 0 || Mut.KF.NumMonsters > Mut.MaxVoteKillMonsters
|| Mut.GameRules.bFinalWave )
{
return;
}
DoEndWave();
break;
case VOTE_READY:
SetReady(VotingHandler.VotedTeam.TeamIndex, true);
break;
case VOTE_UNREADY:
SetReady(VotingHandler.VotedTeam.TeamIndex, false);
break;
case VOTE_TEAMLOCK:
Mut.ScrnGT.LockTeams();
break;
case VOTE_TEAMUNLOCK:
Mut.ScrnGT.UnlockTeams();
break;
case VOTE_INVITE:
Mut.ScrnGT.InvitePlayer(VotingHandler.VotedPlayer);
break;
case VOTE_FF:
Mut.KF.FriendlyFireScale = float(VoteValue)/100.0;
if ( TSCGame(Mut.KF) != none )
TSCGame(Mut.KF).HdmgScale = Mut.KF.FriendlyFireScale;
break;
case VOTE_MAPRESTART:
Level.ServerTravel("?restart",false);
break;
case VOTE_FAKEDPLAYERS:
Mut.ScrnGT.ScrnGRI.FakedPlayers = byte(VoteValue);
Mut.ScrnGT.ScrnGRI.FakedAlivePlayers = byte(VoteValue);
break;
case VOTE_FAKEDCOUNT:
Mut.ScrnGT.ScrnGRI.FakedPlayers = byte(VoteValue);
break;
case VOTE_FAKEDHEALTH:
Mut.ScrnGT.ScrnGRI.FakedAlivePlayers = byte(VoteValue);
break;
case VOTE_DIFF:
Mut.Persistence.Difficulty = byte(VoteValue);
Mut.Persistence.SaveConfig();
break;
case VOTE_RKILL:
if ( VotingHandler.VotedPlayer != none && VotingHandler.VotedPlayer.Pawn != none ) {
VotingHandler.VotedPlayer.Pawn.Suicide();
if ( Reason == "" ) {
VotingHandler.BroadcastMessage(VoteValue $ " killed by referee");
}
else {
VotingHandler.BroadcastMessage(VoteValue $ " killed by referee for " $Reason);
}
}
break;
}
}
function SetReady(byte TeamIndex, bool bReady)
{
local Controller C;
for ( C = Level.ControllerList; C != None; C = C.NextController )
{
if ( C.PlayerReplicationInfo != none && C.bIsPlayer && PlayerController(C) != none
&& C.PlayerReplicationInfo.Team != none
&& C.PlayerReplicationInfo.bWaitingPlayer && !C.PlayerReplicationInfo.bOnlySpectator )
{
C.PlayerReplicationInfo.bReadyToPlay = bReady;
}
}
}
function class<KFMonster> Str2Monster(string MonsterName)
{
MonsterName = caps(MonsterName);
if ( MonsterName == "CLOT" )
return class'ZombieClot';
if ( MonsterName == "CRAWLER" )
return class'ZombieCrawler';
if ( MonsterName == "STALKER" )
return class'ZombieStalker';
if ( MonsterName == "BLOAT" )
return class'ZombieBloat';
if ( MonsterName == "GOREFAST" )
return class'ZombieGorefast';
if ( MonsterName == "SIREN" )
return class'ZombieSiren';
if ( MonsterName == "HUSK" )
return class'ZombieHusk';
if ( MonsterName == "SCRAKE" || MonsterName == "SC" )
return class'ZombieScrake';
if ( MonsterName == "FLESHPOUND" || MonsterName == "FP" )
return class'ZombieFleshpound';
if ( MonsterName == "PAT" || MonsterName == "PATRIARCH" || MonsterName == "BOSS" )
return class'ZombieBoss';
return none;
}
function BlameAll()
{
local Controller P;
local ScrnPlayerController Player;
local ScrnCustomPRI ScrnPRI;
for ( P = Level.ControllerList; P != none; P = P.nextController ) {
Player = ScrnPlayerController(P);
if ( Player != none ) {
ScrnPRI = class'ScrnCustomPRI'.static.FindMe(Player.PlayerReplicationInfo);
if ( ScrnPRI != none ) {
Player.ReceiveLocalizedMessage(class'ScrnBalanceSrv.ScrnBlamedMsg', ScrnPRI.BlameCounter++); // more blame = bigger shit
if ( Player.PlayerReplicationInfo != none && Player.PlayerReplicationInfo.PlayerName ~= "Baron" )
Mut.BroadcastFakedAchievement(0); // blame Baron :)
}
}
}
}
// returns false if monster not found or can't be blamed
function bool BlameMonster(String MonsterName)
{
local class<KFMonster> MC;
local Controller P;
local ScrnPlayerController Player;
MC = Str2Monster(MonsterName);
// don't blame Stalkers and Patriarch, because shit on their head could reveal
// their positions
if ( MC == none || MC == class'ZombieStalker' || MC == class'ZombieBoss' )
return false;
for ( P = Level.ControllerList; P != none; P = P.nextController ) {
Player = ScrnPlayerController(P);
if ( Player != none ) {
Player.ClientMonsterBlamed(MC);
}
}
return true;
}
static function bool IsGoodReason(string Reason)
{
local string a, b;
// good reason contains from at least 2 words, one of them is at least 6 character long
// "n00b" and "screw you" aren't good reasons :)
return Divide(Reason, " ", a, b) && ( len(a) >= 6 || len(b) >= 6);
}
function bool CanEndWave()
{
local Controller C;
local MonsterController MC;
local Monster M;
local KFHumanPawn P;
local int TotalHP;
for ( C = Level.ControllerList; C != None; C = C.NextController ) {
MC = MonsterController(C);
M = Monster(C.Pawn);
if ( MC==none || M == none )
continue;
TotalHP += M.default.Health;
if ( Mut.bVoteKillCheckVisibility ) {
foreach VisibleCollidingActors(class'KFHumanPawn', P, 1000) {
if ( P.Health > 0 && P.Controller != none && P.Controller.bIsPlayer && KF_StoryNPC(P) == none && MC.CanSee(P) )
return false;
}
}
}
return TotalHP <= Mut.MaxVoteKillHP;
}
function DoEndWave()
{
local Monster M;
local int Penalty, TotalPenalty;
foreach DynamicActors(class'Monster', M) {
Penalty = max(M.ScoringValue * Mut.VoteKillPenaltyMult, 0);
VotingHandler.VotedTeam.Score -= Penalty;
TotalPenalty += Penalty;
M.KilledBy(M);
}
if ( TotalPenalty > 0 )
VotingHandler.BroadcastMessage(strEndWavePenalty $ TotalPenalty);
}
function byte GetDifficulty(out string DiffStr)
{
if ( DiffStr == "0" || DiffStr == "DEFAULT" || DiffStr == "OFF" ) {
DiffStr = "Default";
return 2;
}
else if ( DiffStr == "2" || DiffStr == "NORMAL" ) {
DiffStr = "Normal";
return 2;
}
else if ( DiffStr == "4" || DiffStr == "HARD" ) {
DiffStr = "Hard";
return 4;
}
else if ( DiffStr == "5" || DiffStr == "SUICIDAL" || DiffStr == "SUI" ) {
DiffStr = "Suicidal";
return 5;
}
else if ( DiffStr == "6" || DiffStr == "SUICIDAL+" || DiffStr == "SUI+" ) {
DiffStr = "Suicidal+";
return 6;
}
else if ( DiffStr == "7" || DiffStr == "HELLONEARTH" || DiffStr == "HOE" ) {
DiffStr = "HoE";
return 7;
}
else if ( DiffStr == "8" || DiffStr == "HELLONEARTH+" || DiffStr == "HOE+" ) {
DiffStr = "HoE+";
return 8;
}
return 255;
}
state GamePaused
{
Begin:
Level.Pauser = VotingHandler.VoteInitiator.PlayerReplicationInfo;
if ( Level.Pauser != none ) {
// tell players that game is paused
msgPause = strGamePaused;
ReplaceText(msgPause, "%s", string(PauseTime));
VotingHandler.BroadcastMessage(msgPause);
// wait for pause time ends or game resumes by other source (e.g. admin)
while ( PauseTime > 0 && Level.Pauser != none ) {
if ( PauseTime <= 5 )
VotingHandler.BroadcastMessage(String(PauseTime));
else if ( (PauseTime%30 == 0) || (PauseTime < 30 && PauseTime%10 == 0) )
VotingHandler.BroadcastMessage(PauseTime @ strSecondsLeft);
//log(Level.TimeSeconds @ "Sleep", 'ScrnBalance');
sleep(1.0);
PauseTime--;
}
// resume game after pause time ends
if ( Level.Pauser != none ) {
Level.Pauser = none;
VotingHandler.BroadcastMessage(strGameUnpaused);
}
}
GotoState('');
}
defaultproperties
{
strCantEndTrade="Can not end trade time at the current moment"
strTooLate="Too late"
strGamePaused="Game paused for %s seconds"
strSecondsLeft="seconds left"
strGameUnPaused="Game resumed"
strPauseTraderOnly="Game can be paused only during trader time!"
viResume="RESUME GAME"
viEndTrade="END TRADER TIME"
viDifficulty="Difficulty"
strZedSpawnsDoubled="ZED spawn rate doubled!"
strSquadNotFound="Monster squad with a given name not found"
strCantSpawnSquadNow="Can not spawn monsters at this moment"
strSquadList="Avaliable Squads:"
strNotInStoryMode="Not avaliable in Story Mode"
strNotInTSC="Not avaliable in TSC"
strCantEndWaveNow="Can't end the wave now"
strEndWavePenalty="Team charged for premature wave end with $"
strRCommands="R_* commands can be executed only by Referee (Admin rights + Tourney Mode)"
HelpInfo(0)="%gLOCKPERK%w|%gUNLOCKPERK %y<perk_name> %w Disables/Enables perk at the end of the wave"
HelpInfo(1)="%gLOCKTEAM%w|%gUNLOCKTEAM %w Locks/Unlocks teams. Only invited players may join locked team."
HelpInfo(2)="%gPAUSE %yX %w Pause the game for X seconds"
HelpInfo(3)="%gEND TRADE %w Immediately end current trader time and start next wave"
HelpInfo(4)="%gEND WAVE %w Kills last stuck zeds to end the wave"
HelpInfo(5)="%gBLAME %y<player_name> %b[<reason>] %w Blame player [for the <reason>]"
HelpInfo(6)="%gSPEC %y<player_name> %b[<reason>] %w Move player to spectators"
HelpInfo(7)="%gKICK %y<player_name> %b[<reason>] %w Kick player [for the <reason>]"
HelpInfo(8)="%gINVITE %y<player_name> %w Invite player to join locked team."
HelpInfo(9)="%gBORING %w Doubles ZED spawn rate"
HelpInfo(10)="%gSPAWN %y<squad_name> %w Spawns zed squad"
HelpInfo(11)="%gREADY%w|%gUNREADY %w Makes everybody ready/unready to play"
HelpInfo(12)="%gFF %yX %w Set Friendly Fire to X%"
HelpInfo(13)="%gMAP RESTART %w Restarts current map"
HelpInfo(14)="%gFAKED %yX %w Set Faked Players to X (FAKEDCOUNT+FAKEDHEALTH)"
HelpInfo(15)="%gFAKEDCOUNT %yX %w Set Faked Players for zed count calculation"
HelpInfo(16)="%gFAKEDHEALTH %yX %w Set Faked Players for zed health calculation"
HelpInfo(17)="%gDIFF %yX %w Changes map difficulty (2-8) for the next map"
bAlwaysTick=True
}

View file

@ -0,0 +1,8 @@
class ScrnBenelliAmmo extends BenelliAmmo;
//duplicated by goldenbenelliammo
defaultproperties
{
AmmoPickupAmount=12
}

View file

@ -0,0 +1,53 @@
class ScrnBenelliAttachment extends ScrnLaserWeaponAttachment;
defaultproperties
{
LaserAttachmentBone="FlashLight"
mMuzFlashClass=Class'ROEffects.MuzzleFlash3rdKar'
mShellCaseEmitterClass=Class'KFMod.KFShotgunShellSpewer'
MovementAnims(0)="JogF_Shotgun"
MovementAnims(1)="JogB_Shotgun"
MovementAnims(2)="JogL_Shotgun"
MovementAnims(3)="JogR_Shotgun"
TurnLeftAnim="TurnL_Shotgun"
TurnRightAnim="TurnR_Shotgun"
CrouchAnims(0)="CHwalkF_Shotgun"
CrouchAnims(1)="CHwalkB_Shotgun"
CrouchAnims(2)="CHwalkL_Shotgun"
CrouchAnims(3)="CHwalkR_Shotgun"
WalkAnims(0)="WalkF_Shotgun"
WalkAnims(1)="WalkB_Shotgun"
WalkAnims(2)="WalkL_Shotgun"
WalkAnims(3)="WalkR_Shotgun"
CrouchTurnRightAnim="CH_TurnR_Shotgun"
CrouchTurnLeftAnim="CH_TurnL_Shotgun"
IdleCrouchAnim="CHIdle_Shotgun"
IdleWeaponAnim="Idle_Shotgun"
IdleRestAnim="Idle_Shotgun"
IdleChatAnim="Idle_Shotgun"
IdleHeavyAnim="Idle_Shotgun"
IdleRifleAnim="Idle_Shotgun"
FireAnims(0)="Fire_Benelli"
FireAnims(1)="Fire_Benelli"
FireAnims(2)="Fire_Benelli"
FireAnims(3)="Fire_Benelli"
FireAltAnims(0)="Fire_Benelli"
FireAltAnims(1)="Fire_Benelli"
FireAltAnims(2)="Fire_Benelli"
FireAltAnims(3)="Fire_Benelli"
FireCrouchAnims(0)="CHFire_Benelli"
FireCrouchAnims(1)="CHFire_Benelli"
FireCrouchAnims(2)="CHFire_Benelli"
FireCrouchAnims(3)="CHFire_Benelli"
FireCrouchAltAnims(0)="CHFire_Benelli"
FireCrouchAltAnims(1)="CHFire_Benelli"
FireCrouchAltAnims(2)="CHFire_Benelli"
FireCrouchAltAnims(3)="CHFire_Benelli"
HitAnims(0)="HitF_Shotgun"
HitAnims(1)="HitB_Shotgun"
HitAnims(2)="HitL_Shotgun"
HitAnims(3)="HitR_Shotgun"
PostFireBlendStandAnim="Blend_Shotgun"
PostFireBlendCrouchAnim="CHBlend_Shotgun"
MeshRef="KF_Weapons3rd3_Trip.Benelli_3rd"
}

View file

@ -0,0 +1,27 @@
class ScrnBenelliBullet extends ScrnCustomShotgunBullet;
// make Siren's scream accelerate bullet and make higher damage
// made just for fun and to demonstrate penetration altering features
// should be removed later
// (c) PooSH
simulated function float ZedPenDamageReduction(KFMonster Monster)
{
local name SeqName;
local float AnimFrame, AnimRate;
if ( ZombieSiren(Monster) != none) {
Monster.GetAnimParams(1, SeqName, AnimFrame, AnimRate); //thanks to Marco for this one
if (SeqName == 'Siren_Scream') {
return 10;
}
}
return super.ZedPenDamageReduction(Monster);
}
defaultproperties
{
BigZedPenDmgReduction=0.750000
MediumZedPenDmgReduction=1.000000
MyDamageType=Class'KFMod.DamTypeBenelli'
}

View file

@ -0,0 +1,80 @@
class ScrnBenelliFire extends BenelliFire;
var float AimedSpread; //spead while aiming down the sights
simulated function bool AllowFire()
{
//changed to 1 -- PooSH
if( KFWeapon(Weapon).bIsReloading && KFWeapon(Weapon).MagAmmoRemaining < 1)
return false;
if(KFPawn(Instigator).SecondaryItem!=none)
return false;
if( KFPawn(Instigator).bThrowingNade )
return false;
if( Level.TimeSeconds - LastClickTime>FireRate )
{
LastClickTime = Level.TimeSeconds;
}
if( KFWeaponShotgun(Weapon).MagAmmoRemaining<1 )
return false;
return super(WeaponFire).AllowFire();
}
event ModeDoFire()
{
local float Rec;
if (!AllowFire())
return;
if( KFWeap.bAimingRifle )
Spread = AimedSpread;
else
Spread = Default.Spread;
Rec = GetFireSpeed();
FireRate = default.FireRate/Rec;
FireAnimRate = default.FireAnimRate*Rec;
Rec = 1;
if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
{
Spread *= KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.ModifyRecoilSpread(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self, Rec);
}
if( !bFiringDoesntAffectMovement )
{
if (FireRate > 0.25)
{
Instigator.Velocity.x *= 0.1;
Instigator.Velocity.y *= 0.1;
}
else
{
Instigator.Velocity.x *= 0.5;
Instigator.Velocity.y *= 0.5;
}
}
Super(BaseProjectileFire).ModeDoFire();
// client
if (Instigator.IsLocallyControlled())
{
HandleRecoil(Rec);
}
}
defaultproperties
{
AimedSpread=750.000000
maxVerticalRecoilAngle=1250
maxHorizontalRecoilAngle=700
AmmoClass=Class'ScrnBalanceSrv.ScrnBenelliAmmo'
ProjectileClass=Class'ScrnBalanceSrv.ScrnBenelliBullet'
Spread=1075.000000
}

View file

@ -0,0 +1,10 @@
class ScrnBenelliPickup extends BenelliPickup;
defaultproperties
{
cost=1500
Description="A military tactical shotgun with semi automatic fire capability. Holds up to 6 shells. Special shell construction allow pellets to penetrate fat much easier."
ItemName="Combat Shotgun SE"
ItemShortName="Combat Shotgun SE"
InventoryType=Class'ScrnBalanceSrv.ScrnBenelliShotgun'
}

View file

@ -0,0 +1,329 @@
class ScrnBenelliShotgun extends BenelliShotgun;
var bool bChamberThisReload; //if full reload is uninterrupted, play chambering animation
var vector ReloadViewOffset, ReloadViewOffsetInterp, ReloadViewOffsetValue, TargetViewOffset; //offset used during reloads
var float ReloadTweenStartTime, ReloadTweenEndTime, ReloadTweenRate;
//copypaste from Scrn M14 and vanilla M14 for laser
var LaserDot Spot; // The first person laser site dot
var() float SpotProjectorPullback; // Amount to pull back the laser dot projector from the hit location
var bool bLaserActive; // The laser site is active
var LaserBeamEffect Beam; // Third person laser beam effect
var() class<InventoryAttachment> LaserAttachmentClass; // First person laser attachment class
var Actor LaserAttachment; // First person laser attachment
var() byte LaserType; //current laser type
var const class<ScrnLocalLaserDot> LaserDotClass;
var ScrnLocalLaserDot LaserDot;
var name LaserAttachmentBone;
var float FireSpotRenrerTime;
//laser stuff
replication
{
reliable if(Role < ROLE_Authority)
ServerSetLaserType;
}
simulated function Destroyed()
{
if (Spot != None)
Spot.Destroy();
if (Beam != None)
Beam.Destroy();
if (LaserDot != None)
LaserDot.Destroy();
if (LaserAttachment != None)
LaserAttachment.Destroy();
super(KFWeapon).Destroyed();
}
//bring Laser to current state, which is indicating by LaserType
simulated function ApplyLaserState()
{
//bLaserActive = LaserType > 0;
LaserType = 1; //always red laser
bLaserActive = LaserType > 0;
if( Role < ROLE_Authority )
ServerSetLaserType(LaserType);
if ( ThirdPersonActor != none )
ScrnLaserWeaponAttachment(ThirdPersonActor).SetLaserType(LaserType);
if ( !Instigator.IsLocallyControlled() )
return;
if( bLaserActive ) {
if ( LaserDot == none )
LaserDot = Spawn(LaserDotClass, self);
LaserDot.SetLaserType(LaserType);
//spawn 1-st person laser attachment for weapon owner
if ( LaserAttachment == none ) {
LaserAttachment = Spawn(LaserAttachmentClass,,,,);
AttachToBone(LaserAttachment, LaserAttachmentBone);
}
ConstantColor'ScrnTex.Laser.LaserColor'.Color =
LaserDot.GetLaserColor(); // LaserAttachment's color
LaserAttachment.bHidden = false;
}
else {
if ( LaserAttachment != none )
LaserAttachment.bHidden = true;
if ( LaserDot != none )
LaserDot.Destroy(); //bHidden = true;
}
}
// Toggle laser modes: RED/GREEN/OFF
simulated function ToggleLaser()
{
if( !Instigator.IsLocallyControlled() )
return;
if ( (++LaserType) > 2 )
LaserType = 0;
ApplyLaserState();
}
simulated function BringUp(optional Weapon PrevWeapon)
{
ApplyLaserState();
Super.BringUp(PrevWeapon);
if ( Level.NetMode != NM_DedicatedServer )
{
ReloadViewOffset = Vect(0,0,0);
}
}
simulated function ClientReload()
{
bChamberThisReload = ( MagAmmoRemaining == 0 && (AmmoAmount(0) - MagAmmoRemaining > MagCapacity) ); //for chambering animation
Super.ClientReload();
TargetViewOffset = ReloadViewOffsetValue;
ReloadTweenStartTime = Level.TimeSeconds;
ReloadTweenEndTime = Level.TimeSeconds + ReloadTweenRate;
ReloadViewOffsetInterp = ReloadViewOffset; //store values for interpolation
}
// Set the new fire mode on the server
function ServerSetLaserType(byte NewLaserType)
{
LaserType = NewLaserType;
bLaserActive = NewLaserType > 0;
ScrnLaserWeaponAttachment(ThirdPersonActor).SetLaserType(LaserType);
}
simulated function bool PutDown()
{
TurnOffLaser();
if( Instigator.IsLocallyControlled() )
{
//don't do this stuff on dedicated servers
TargetViewOffset = Vect(0,0,0);
ReloadTweenStartTime = Level.TimeSeconds;
ReloadTweenEndTime = Level.TimeSeconds + ReloadTweenRate;
ReloadViewOffsetInterp = ReloadViewOffset; //store values for interpolation
}
return super(KFWeapon).PutDown();
}
simulated function TurnOffLaser()
{
if( !Instigator.IsLocallyControlled() )
return;
if( Role < ROLE_Authority )
ServerSetLaserType(0);
bLaserActive = false;
//don't change Laser type here, because we need to restore it state
//when next time weapon will be bringed up
if ( LaserAttachment != none )
LaserAttachment.bHidden = true;
if (LaserDot != None)
LaserDot.Destroy();
}
//tweens to reload offset when reloading and tweens back to 0,0,0 when reload ends or is interrupted by zoom or fire
simulated function TweenToReloadOffset()
{
local float Alpha; //for lerp
if (ReloadTweenEndTime == 0)
{
return; //do nothing
}
if (Level.TimeSeconds > ReloadTweenEndTime)
{
ReloadViewOffset = TargetViewOffset; //set target
ReloadTweenEndTime = 0; //set this to 0
}
Alpha = (Level.TimeSeconds-ReloadTweenStartTime)/ReloadTweenRate; //returns float between 0 and 1
if ( Level.NetMode != NM_DedicatedServer )
{
//lerp from current interp value to target
ReloadViewOffset.X = Lerp(Alpha, ReloadViewOffsetInterp.X, TargetViewOffset.X);
ReloadViewOffset.Y = Lerp(Alpha, ReloadViewOffsetInterp.Y, TargetViewOffset.Y);
ReloadViewOffset.Z = Lerp(Alpha, ReloadViewOffsetInterp.Z, TargetViewOffset.Z);
}
}
//added function to calculate and apply reload view offset
simulated function WeaponTick(float dt)
{
Super.WeaponTick(dt);
TweenToReloadOffset();
}
// Server forces the reload to be cancelled
simulated function bool InterruptReload()
{
//solo testing kek
if ( Level.NetMode != NM_DedicatedServer )
{
TargetViewOffset = Vect(0,0,0);
ReloadTweenStartTime = Level.TimeSeconds;
ReloadTweenEndTime = Level.TimeSeconds + ReloadTweenRate;
ReloadViewOffsetInterp = ReloadViewOffset; //store values for interpolation
}
return Super.InterruptReload();
}
//supports laser and reload view offset
simulated function RenderOverlays( Canvas Canvas )
{
local vector DrawOffset;
local int i;
local Vector StartTrace, EndTrace;
local Vector HitLocation, HitNormal;
local Actor Other;
local vector X,Y,Z;
local coords C;
local KFShotgunFire KFSGM;
local array<Actor> HitActors;
if (Instigator == None)
return;
if ( Instigator.Controller != None )
Hand = Instigator.Controller.Handedness;
if ((Hand < -1.0) || (Hand > 1.0))
return;
// draw muzzleflashes/smoke for all fire modes so idle state won't
// cause emitters to just disappear
for ( i = 0; i < NUM_FIRE_MODES; ++i ) {
if (FireMode[i] != None)
FireMode[i].DrawMuzzleFlash(Canvas);
}
DrawOffset = (90/DisplayFOV * ReloadViewOffset) >> Instigator.GetViewRotation(); //calculate additional offset
SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) + DrawOffset); //add additional offset
SetRotation( Instigator.GetViewRotation() + ZoomRotInterp);
KFSGM = KFShotgunFire(FireMode[0]);
// Handle drawing the laser dot
if ( LaserDot != None )
{
//move LaserDot during fire animation too -- PooSH
if( bIsReloading || (Level.TimeSeconds < KFSGM.LastClickTime + FireSpotRenrerTime) )
{
C = GetBoneCoords(LaserAttachmentBone);
X = C.XAxis;
Y = C.YAxis;
Z = C.ZAxis;
}
else
GetViewAxes(X, Y, Z);
StartTrace = Instigator.Location + Instigator.EyePosition();
EndTrace = StartTrace + 65535 * X; //65535
while (true) {
Other = Trace(HitLocation, HitNormal, EndTrace, StartTrace, true);
if ( ROBulletWhipAttachment(Other) != none ) {
HitActors[HitActors.Length] = Other;
Other.SetCollision(false);
StartTrace = HitLocation + X;
}
else {
if (Other != None && Other != Instigator && Other.Base != Instigator )
EndBeamEffect = HitLocation;
else
EndBeamEffect = EndTrace;
break;
}
}
// restore collision
for ( i=0; i<HitActors.Length; ++i )
HitActors[i].SetCollision(true);
LaserDot.SetLocation(EndBeamEffect - X*LaserDot.ProjectorPullback);
if( Pawn(Other) != none ) {
LaserDot.SetRotation(Rotator(X));
LaserDot.SetDrawScale(LaserDot.default.DrawScale * 0.5);
}
else if( HitNormal == vect(0,0,0) ) {
LaserDot.SetRotation(Rotator(-X));
LaserDot.SetDrawScale(LaserDot.default.DrawScale);
}
else {
LaserDot.SetRotation(Rotator(-HitNormal));
LaserDot.SetDrawScale(LaserDot.default.DrawScale);
}
}
//PreDrawFPWeapon(); // Laurent -- Hook to override things before render (like rotation if using a staticmesh)
bDrawingFirstPerson = true;
Canvas.DrawActor(self, false, false, DisplayFOV);
bDrawingFirstPerson = false;
}
simulated function ClientFinishReloading()
{
bIsReloading = false;
//do reload tween stuff
TargetViewOffset = Vect(0,0,0);
ReloadTweenStartTime = Level.TimeSeconds;
ReloadTweenEndTime = Level.TimeSeconds + ReloadTweenRate;
ReloadViewOffsetInterp = ReloadViewOffset; //store values for interpolation
//play chambering animation if finished reloading from empty
if ( !bChamberThisReload )
{
PlayIdle();
}
bChamberThisReload = false;
if(Instigator.PendingWeapon != none && Instigator.PendingWeapon != self)
Instigator.Controller.ClientSwitchToBestWeapon();
}
defaultproperties
{
ReloadViewOffsetValue=(X=10.000000,Y=-5.000000,Z=-10.000000)
ReloadTweenRate=0.200000
LaserAttachmentClass=Class'ScrnBalanceSrv.ScrnLaserAttachmentFirstPerson'
LaserDotClass=Class'ScrnBalanceSrv.ScrnLocalLaserDot'
LaserAttachmentBone="LightBone"
FireSpotRenrerTime=1.500000
ReloadRate=0.750000
ReloadAnimRate=1.074000
ModeSwitchAnim="LightOn"
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnBenelliFire'
Description="A military tactical shotgun with semi automatic fire capability. Holds up to 6 shells. Special shell construction allow pellets to penetrate fat much easier."
PickupClass=Class'ScrnBalanceSrv.ScrnBenelliPickup'
PlayerViewPivot=(Pitch=-47,Yaw=-5)
AttachmentClass=Class'ScrnBalanceSrv.ScrnBenelliAttachment'
ItemName="Combat Shotgun SE"
}

View file

@ -0,0 +1,71 @@
class ScrnBlamedMsg extends CriticalEventPlus
abstract;
var array<localized string>Messages;
var texture Picture;
var string PictureRef;
static function RenderComplexMessage(
Canvas C,
out float XL,
out float YL,
optional String MessageString,
optional int Switch,
optional PlayerReplicationInfo RelatedPRI_1,
optional PlayerReplicationInfo RelatedPRI_2,
optional Object OptionalObject // must be ScrnAchievementInfo
)
{
local float TextWidth, TextHeight;
local float IconSize;
local float y, ty;
local int i;
IconSize = C.ClipY * fmin(0.9, 0.25 + Switch*0.05);
C.Style = ERenderStyle.STY_Alpha;
C.Font = class'ScrnBalanceSrv.ScrnHUD'.static.LoadSmallFontStatic(7);
C.StrLen(default.Messages[0], TextWidth, TextHeight);
y = max( (C.ClipY - IconSize ) / 2, 0 );
ty = max( y - TextHeight * default.Messages.Length, C.ClipY * 0.12 );
for ( i = 0; i < default.Messages.Length; ++i ) {
C.StrLen(default.Messages[i], TextWidth, TextHeight);
C.SetPos(c.ClipX - TextWidth - 4, ty);
C.DrawTextClipped(default.Messages[i]);
ty += TextHeight;
}
C.SetPos(C.ClipX - IconSize, y);
C.DrawTile(default.Picture, IconSize, IconSize, 0, 0, 256, 256);
// C.SetPos(0, y);
// C.DrawTile(default.Picture, IconSize, IconSize, 0, 0, 256, 256);
}
static function ClientReceive(
PlayerController P,
optional int Switch,
optional PlayerReplicationInfo RelatedPRI_1,
optional PlayerReplicationInfo RelatedPRI_2,
optional Object OptionalObject
)
{
if ( default.Picture == none )
default.Picture = texture(DynamicLoadObject(default.PictureRef, class'texture'));
Super.ClientReceive(P,Switch,RelatedPRI_1,RelatedPRI_2,OptionalObject);
}
defaultproperties
{
Messages(0)="You are blamed by the team!"
Messages(1)="As a punishment you have to"
Messages(2)="look at this for 2 minutes:"
PictureRef="ScrnTex.HUD.Crap256"
bComplexString=True
Lifetime=120
DrawColor=(B=64,G=64,R=255)
PosY=0.800000
FontSize=5
}

View file

@ -0,0 +1,228 @@
class ScrnBoomStick extends BoomStick;
var() float SingleShellReloadRatio; //comparing to full reload rate. 2.0 = twice faster reload
var string NewAnimRef;
var string OldAnimRef;
var MeshAnimation NewAnim;
var float ReloadHalfAnimRate; //animation playrate modifier for reload_half
var name ReloadHalfAnim;
replication
{
reliable if(Role == ROLE_Authority)
ClientPlayReloadAnim, ClientSetWaitingToLoadShotty;
}
static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount)
{
local ScrnBoomStick spawned;
super.PreloadAssets(Inv, bSkipRefCount);
if (default.NewAnimRef == "")
return;
default.NewAnim = MeshAnimation(DynamicLoadObject(default.NewAnimRef, class'MeshAnimation', true));
spawned = ScrnBoomStick(Inv);
if( spawned != none ) {
spawned.NewAnim = default.NewAnim;
spawned.AddNewAnim();
}
}
static function bool UnloadAssets()
{
default.NewAnim = none;
return super.UnloadAssets();
}
//new anim in PostBeginPlay because adding it in PreloadAssets didn't work
simulated function PostBeginPlay()
{
super.PostBeginPlay();
AddNewAnim();
}
simulated function AddNewAnim()
{
if (NewAnim == none || NewAnimRef == "")
return;
LinkSkelAnim(NewAnim); //load new anim
//for some reason linking the new anim removed the link to the old one, so we need to load it again
LinkSkelAnim(MeshAnimation(DynamicLoadObject(OldAnimRef, class'MeshAnimation', true)));
}
simulated function WeaponTick(float dt)
{
super(KFWeaponShotgun).WeaponTick(dt);
if( Role == ROLE_Authority )
{
if( bWaitingToLoadShotty )
{
CurrentReloadCountDown -= dt;
if( CurrentReloadCountDown <= 0 )
{
if( AmmoAmount(0) > 0 )
{
MagAmmoRemaining = Min(AmmoAmount(0), 2);
SingleShotCount = MagAmmoRemaining;
ClientSetSingleShotCount(SingleShotCount);
bWaitingToLoadShotty = false;
ClientSetWaitingToLoadShotty(bWaitingToLoadShotty); // replicate it to clients too
NetUpdateTime = Level.TimeSeconds - 1;
}
}
}
if( SingleShotReplicateCountdown > 0 )
{
SingleShotReplicateCountdown -= dt;
if( SingleShotReplicateCountdown <= 0 )
{
ClientSetSingleShotCount(SingleShotCount);
}
}
}
}
function SetPendingReload()
{
if ( !bWaitingToLoadShotty && AmmoAmount(0) > 0 ) {
bWaitingToLoadShotty = true;
ClientSetWaitingToLoadShotty(bWaitingToLoadShotty); // replicate it to clients too
CurrentReloadCountDown = ReloadCountDown;
}
}
simulated function bool ConsumeAmmo( int Mode, float Load, optional bool bAmountNeededIsMax )
{
local bool result;
result = super.ConsumeAmmo(0, Load, bAmountNeededIsMax);
if ( AmmoAmount(0) == 0 && MagAmmoRemaining == 0 ) {
SingleShotCount = 0;
if ( bWaitingToLoadShotty ) {
bWaitingToLoadShotty = false;
ClientSetWaitingToLoadShotty(bWaitingToLoadShotty); // replicate it to clients too
}
}
return result;
}
simulated function ClientSetWaitingToLoadShotty(bool bNewWaitingToLoadShotty)
{
bWaitingToLoadShotty = bNewWaitingToLoadShotty;
}
simulated function ClientPlayReloadAnim(float AnimRatio)
{
if (AnimRatio ~= 0)
AnimRatio = 1.0;
bWaitingToLoadShotty = true;
if ( NewAnim != none )
{
PlayAnim(ReloadHalfAnim, ReloadHalfAnimRate, 0.1); //noreload multi because no firerate bonus for boomstick
}
else
{
PlayAnim(BoomStickAltFire(FireMode[0]).FireLastAnim,
FireMode[0].FireAnimRate * AnimRatio,
FireMode[0].TweenTime, 0);
SetAnimFrame(4, 0 , 1); //skip fire animation and jump to reload
}
}
//allow reload single shell
function bool AllowReload()
{
if ( bWaitingToLoadShotty )
return false;
return super(KFWeaponShotgun).AllowReload();
}
exec function ReloadMeNow()
{
if(!AllowReload())
return;
if ( SingleShotCount < MagCapacity && !bWaitingToLoadShotty && AmmoAmount(0) > 0 ) {
bWaitingToLoadShotty = true;
if ( SingleShotCount > 0 ) {
CurrentReloadCountDown = ReloadCountDown / SingleShellReloadRatio;
ClientPlayReloadAnim(SingleShellReloadRatio);
}
else {
CurrentReloadCountDown = ReloadCountDown;
ClientPlayReloadAnim(1.0);
}
}
}
simulated function bool PutDown()
{
if ( bWaitingToLoadShotty && Instigator != none && Instigator.PendingWeapon != none && AmmoAmount(0) > 1 ) {
Instigator.PendingWeapon = none;
return false;
}
return super.PutDown();
}
function GiveAmmo(int m, WeaponPickup WP, bool bJustSpawned)
{
super(KFWeapon).GiveAmmo(m,WP,bJustSpawned);
// Update the singleshotcount if we pick this weapon up
if( WP != none )
{
if( m == 0 && AmmoAmount(0) < 2 )
{
SingleShotCount = AmmoAmount(0);
MagAmmoRemaining = SingleShotCount;
ClientSetSingleShotCount(SingleShotCount);
NetUpdateTime = Level.TimeSeconds - 1;
}
else if( BoomStickPickup(WP) != none )
{
SingleShotCount = BoomStickPickup(WP).SingleShotCount;
MagAmmoRemaining = SingleShotCount;
ClientSetSingleShotCount(SingleShotCount);
NetUpdateTime = Level.TimeSeconds - 1;
}
}
}
simulated function ClientSetSingleShotCount(float NewSingleShotCount)
{
SingleShotCount = NewSingleShotCount;
MagAmmoRemaining = SingleShotCount;
}
defaultproperties
{
SingleShellReloadRatio=1.750000
NewAnimRef="ScrnAnims.boomstick_anim_new"
OldAnimRef="KF_Weapons_Trip.boomstick_anim"
ReloadHalfAnimRate=1.463300
ReloadHalfAnim="reload_half"
ReloadRate=2.750000
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnBoomStickAltFire'
FireModeClass(1)=Class'ScrnBalanceSrv.ScrnBoomStickFire'
Description="This is my BOOMstick (c) Ash, Evil Dead - Army of Darkness, 1992.|Has been used through the centuries to hunt down Demons, Aliens and Zombies. Now it's time for the ZEDs.|Can shoot from one or two barrels simultaneousely. Single shell reload is avaliable."
PickupClass=Class'ScrnBalanceSrv.ScrnBoomStickPickup'
ItemName="Boomstick"
}

View file

@ -0,0 +1,32 @@
//=============================================================================
// BoomStick Single Fire
//=============================================================================
class ScrnBoomStickAltFire extends BoomStickAltFire;
simulated function bool AllowFire()
{
local ScrnBoomStick HSg;
HSg = ScrnBoomStick(Weapon);
if (HSg == none) {
log("ScrnBoomStickAltFire's Weapon is " $ Weapon $ " not ScrnBoomStick!", 'ScrnBalance');
return super.AllowFire(); // wtf?
}
if ( HSg.bWaitingToLoadShotty || HSg.AmmoAmount(ThisModeNum) < AmmoPerFire )
return false;
if ( HSg.SingleShotCount <= 0 ) {
if ( HSg.AmmoAmount(0) > 0 ) {
HSg.ReloadMeNow();
}
return false;
}
return true;
}
defaultproperties
{
ProjectileClass=Class'ScrnBalanceSrv.ScrnBoomStickBullet'
}

View file

@ -0,0 +1,11 @@
class ScrnBoomStickBullet extends ScrnCustomShotgunBullet;
defaultproperties
{
MediumZedPenDmgReduction=1.000000
MaxPenetrations=4
PenDamageReduction=0.800000
Damage=50.000000
MomentumTransfer=60000.000000
MyDamageType=Class'KFMod.DamTypeDBShotgun'
}

View file

@ -0,0 +1,32 @@
//=============================================================================
// BoomStick Dual Fire
//=============================================================================
class ScrnBoomStickFire extends BoomStickFire;
simulated function bool AllowFire()
{
local ScrnBoomStick HSg;
HSg = ScrnBoomStick(Weapon);
if (HSg == none) {
log("ScrnBoomStickFire's Weapon is " $ Weapon $ " not ScrnBoomStick!", 'ScrnBalance');
return super.AllowFire(); // wtf?
}
if ( HSg.bWaitingToLoadShotty || HSg.AmmoAmount(ThisModeNum) < AmmoPerFire)
return false;
if ( HSg.SingleShotCount <= 0 ) {
if ( HSg.AmmoAmount(0) > 0 ) {
HSg.ReloadMeNow();
}
return false;
}
return true;
}
defaultproperties
{
ProjectileClass=Class'ScrnBalanceSrv.ScrnBoomStickBullet'
}

View file

@ -0,0 +1,11 @@
class ScrnBoomStickPickup extends BoomStickPickup;
defaultproperties
{
cost=1000
AmmoCost=45
Description="This is my BOOMstick (c) Ash, Evil Dead - Army of Darkness, 1992.|Has been used through the centuries to hunt down Demons, Aliens and Zombies. Now it's time for the ZEDs.|Can shoot from one or two barrels simultaneousely. Single shell reload is avaliable."
ItemName="Hunting Shotgun SE"
ItemShortName="Boomstick"
InventoryType=Class'ScrnBalanceSrv.ScrnBoomStick'
}

View file

@ -0,0 +1,11 @@
class ScrnBullpup extends Bullpup
config(user);
defaultproperties
{
Weight=4.000000
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnBullpupFire'
Description="If you found Bullpup on a map, then it probably belongs to [REB]Mike1. Mike has more than 1000 gameplay hours in KF by using only a Bullpup."
PickupClass=Class'ScrnBalanceSrv.ScrnBullpupPickup'
ItemName="Mike's Bullpup"
}

View file

@ -0,0 +1,7 @@
class ScrnBullpupAmmo extends BullpupAmmo;
defaultproperties
{
InitialAmount=200
PickupClass=Class'ScrnBalanceSrv.ScrnBullpupAmmoPickup'
}

View file

@ -0,0 +1,6 @@
class ScrnBullpupAmmoPickup extends BullpupAmmoPickup;
defaultproperties
{
InventoryType=Class'ScrnBalanceSrv.ScrnBullpupAmmo'
}

View file

@ -0,0 +1,131 @@
class ScrnBullpupFire extends BullpupFire;
//add 1 penetration
function DoTrace(Vector Start, Rotator Dir)
{
local Vector X,Y,Z, End, HitLocation, HitNormal, ArcEnd;
local Actor Other;
local byte HitCount,HCounter;
local float HitDamage;
local array<int> HitPoints;
local KFPawn HitPawn;
local array<Actor> IgnoreActors;
local Actor DamageActor;
local int i;
MaxRange();
Weapon.GetViewAxes(X, Y, Z);
if ( Weapon.WeaponCentered() )
{
ArcEnd = (Instigator.Location + Weapon.EffectOffset.X * X + 1.5 * Weapon.EffectOffset.Z * Z);
}
else
{
ArcEnd = (Instigator.Location + Instigator.CalcDrawOffset(Weapon) + Weapon.EffectOffset.X * X +
Weapon.Hand * Weapon.EffectOffset.Y * Y + Weapon.EffectOffset.Z * Z);
}
X = Vector(Dir);
End = Start + TraceRange * X;
HitDamage = DamageMax;
While( (HitCount++)<2 ) // 1 penetration
{
DamageActor = none;
Other = Instigator.HitPointTrace(HitLocation, HitNormal, End, HitPoints, Start,, 1);
if( Other==None )
{
Break;
}
else if( Other==Instigator || Other.Base == Instigator )
{
IgnoreActors[IgnoreActors.Length] = Other;
Other.SetCollision(false);
Start = HitLocation;
Continue;
}
if( ExtendedZCollision(Other)!=None && Other.Owner!=None )
{
IgnoreActors[IgnoreActors.Length] = Other;
IgnoreActors[IgnoreActors.Length] = Other.Owner;
Other.SetCollision(false);
Other.Owner.SetCollision(false);
DamageActor = Pawn(Other.Owner);
}
if ( !Other.bWorldGeometry && Other!=Level )
{
HitPawn = KFPawn(Other);
if ( HitPawn != none )
{
// Hit detection debugging
/*log("PreLaunchTrace hit "$HitPawn.PlayerReplicationInfo.PlayerName);
HitPawn.HitStart = Start;
HitPawn.HitEnd = End;*/
if(!HitPawn.bDeleteMe)
HitPawn.ProcessLocationalDamage(int(HitDamage), Instigator, HitLocation, Momentum*X,DamageType,HitPoints);
// Hit detection debugging
/*if( Level.NetMode == NM_Standalone)
HitPawn.DrawBoneLocation();*/
IgnoreActors[IgnoreActors.Length] = Other;
IgnoreActors[IgnoreActors.Length] = HitPawn.AuxCollisionCylinder;
Other.SetCollision(false);
HitPawn.AuxCollisionCylinder.SetCollision(false);
DamageActor = Other;
}
else
{
if( KFMonster(Other)!=None )
{
IgnoreActors[IgnoreActors.Length] = Other;
Other.SetCollision(false);
DamageActor = Other;
}
else if( DamageActor == none )
{
DamageActor = Other;
}
Other.TakeDamage(int(HitDamage), Instigator, HitLocation, Momentum*X, DamageType);
}
if( (HCounter++)>=3 || Pawn(DamageActor)==None )
{
Break;
}
if ( KFMonster(Other) != none && KFMonster(Other).default.Health >= 500 && !KFMonster(Other).bDecapitated )
break;
// 1 bullet penetration vs small zeds
HitDamage*=0.75;
Start = HitLocation;
}
else if ( HitScanBlockingVolume(Other)==None )
{
if( KFWeaponAttachment(Weapon.ThirdPersonActor)!=None )
KFWeaponAttachment(Weapon.ThirdPersonActor).UpdateHit(Other,HitLocation,HitNormal);
Break;
}
}
// Turn the collision back on for any actors we turned it off
if ( IgnoreActors.Length > 0 )
{
for (i=0; i<IgnoreActors.Length; i++)
{
if ( IgnoreActors[i] != none )
IgnoreActors[i].SetCollision(true);
}
}
}
defaultproperties
{
DamageType=Class'ScrnBalanceSrv.ScrnDamTypeBullpup'
DamageMin=28
DamageMax=28
AmmoClass=Class'ScrnBalanceSrv.ScrnBullpupAmmo'
}

View file

@ -0,0 +1,11 @@
class ScrnBullpupPickup extends BullpupPickup;
defaultproperties
{
Weight=4.000000
cost=200
Description="If you found Bullpup on a map, then it probably belongs to [REB]Mike1. Mike has more than 1000 gameplay hours in KF by using only a Bullpup."
ItemName="Mike's Bullpup"
ItemShortName="Mike's Bullpup"
InventoryType=Class'ScrnBalanceSrv.ScrnBullpup'
}

View file

@ -0,0 +1,323 @@
// Alternate Burning Mechanism
// Big thanx to Scary Ghost for inspiring me to do it this way
class ScrnBurnMech extends Info;
struct BurningMonster {
var KFMonster Victim;
var Pawn Instigator;
var int BurnDown;
var int BurnDamage;
var class<DamageType> FireDamageClass;
var float NextBurnTime;
var int BurnTicks; //how many ticks zed is already burning
var int FlareCount; //how many flares are burning inside a zed
var int TotalInputDamage; // total amount of incoming damage
};
var array<BurningMonster> Monsters;
var array<ScrnFlareCloud> FlareClouds;
var int BurnDuration; // tick count from ignition till the end of burning
var int BurnInCount; // tick count from ignition till reaching the maximum burn damage
var float BurnPeriod; // how often zeds will receive damage from burning
var(Sound) Sound FlareSound;
var string FlareSoundRef;
var bool bOutputDamage;
function PostBeginPlay()
{
FlareSound = sound(DynamicLoadObject(FlareSoundRef, class'Sound', true));
}
function int FindMonsterIndex(KFMonster Monster )
{
local int i;
for ( i = 0; i < Monsters.Length; ++i ) {
if ( Monsters[i].Victim == Monster )
return i;
}
return -1;
}
function int GetAvgBurnDamage(int BurnDown, int InitialDamage)
{
local float AvgTickInc;
// Fire damage is increasing by (3-4 points per tick) * 1.5. 10 ticks total. Average = sum / 2 = 18.
// Ignition takes 2 ticks, then average, constant damage is applied till the end of burning process
// Total DoT is weaker comparing to original game due to 2 less ticks and burn-in damage decrement
if ( class'ScrnBalance'.default.Mut.bHardcore || BurnDown >= BurnDuration )
AvgTickInc = 6;
else if ( BurnDown > (BurnDuration - BurnInCount) )
AvgTickInc = 12;
else
AvgTickInc = 18;
return InitialDamage + AvgTickInc;
}
function FlareMonster(int idx)
{
local ScrnPlayerController InstigatorController;
local ScrnPlayerController PC;
local Controller C;
Monsters[idx].Victim.AmbientSound = FlareSound;
if ( Monsters[idx].Instigator != none )
InstigatorController = ScrnPlayerController(Monsters[idx].Instigator.Controller);
for ( C = Level.ControllerList; C != none; C = C.NextController ) {
PC = ScrnPlayerController(C);
if ( PC != none && (PC == InstigatorController || PC.LineOfSightTo(Monsters[idx].Victim)) ) {
PC.ClientFlareDamage(Monsters[idx].Victim, Monsters[idx].BurnDamage/4, Monsters[idx].BurnDown);
}
}
}
function StopFlareFX(KFMonster Monster)
{
if ( Monster.AmbientSound == FlareSound )
Monster.AmbientSound = none;
}
function StopBurningBehavior(KFMonster Monster)
{
Monster.SetTimer(0, false);
Monster.bSTUNNED = false; // maybe timer was set to turn it off?
Monster.bBurnified = false;
Monster.BurnDown = 0;
//if monster is raged don't slow him down
Monster.GroundSpeed = max(Monster.GroundSpeed, Monster.default.GroundSpeed);
Monster.UnSetBurningBehavior();
Monster.RemoveFlamingEffects();
Monster.StopBurnFX();
StopFlareFX(Monster);
}
function MakeBurnDamage(KFMonster Victim, int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Momentum,
class<DamageType> DamType, optional int HitIndex)
{
local bool bIncDamage;
local int OldHealth;
local int i, FreeSlot;
local class<ScrnDamTypeFlare> FlareDamType;
local float AdjustedFlareCount;
// ScrnDamTypeHuskGun_Alt required for achievement
bIncDamage = ClassIsChildOf(DamType, class'DamTypeMAC10MPInc') || DamType == class'ScrnBalanceSrv.ScrnDamTypeHuskGun_Alt';
FlareDamType = class<ScrnDamTypeFlare>(DamType);
// check if zed is already burning
FreeSlot = Monsters.Length;
for( i = 0; i < Monsters.Length; ++i ) {
if ( Monsters[i].Victim == none ) {
if ( FreeSlot == Monsters.Length )
FreeSlot = i;
}
else if ( Monsters[i].Victim == Victim
// Flare and regular burn damages occupy different slots
&& (FlareDamType == none) == (Monsters[i].FlareCount == 0) )
{
if ( FlareDamType != none ) {
// Flares make incremental damage, i.e. each next flare raises damage per tick
// Adjust flare count for this amount of damage.
// For instance, monster was hit by 4 small flares (15 damage each) and now hit by
// a big flare which causing 60 damage. Total flare count = 5, but if scaled by current damage,
// then adjusted flare count = 2.
AdjustedFlareCount = float(Monsters[i].TotalInputDamage) / Damage;
if ( bOutputDamage && InstigatedBy != none && PlayerController(InstigatedBy.Controller) != none )
PlayerController(InstigatedBy.Controller).ClientMessage(
"AdjustedFlareCount="$AdjustedFlareCount
@ "TotalInputDamage="$Monsters[i].TotalInputDamage
@ "Damage="$Damage
);
Monsters[i].BurnDown += FlareDamType.default.BurnTimeBoost;
Monsters[i].BurnDown = max(Monsters[i].BurnDown,
FlareDamType.default.MinBurnTime + AdjustedFlareCount * FlareDamType.default.BurnTimeInc);
Monsters[i].BurnDown = min(Monsters[i].BurnDown, FlareDamType.default.MaxBurnTime);
Monsters[i].BurnDamage += max(Damage * FlareDamType.default.iDoT_MinBoostRatio,
Damage / (1.0 + AdjustedFlareCount * FlareDamType.default.iDoT_FadeFactor));
Monsters[i].FlareCount++;
}
else if ( Damage >= Monsters[i].BurnDamage * 0.8 ) { //lower fire damage can't increase burn ticks, e.g. shooting with MAC10 after Husk gun
//received extra burn damage while still burning
Monsters[i].BurnDown = max(Monsters[i].BurnDown, BurnDuration - BurnInCount); //increase burn time to the maximum again (excluding 2 burn-in ticks)
Monsters[i].BurnDamage = max(Damage, Monsters[i].BurnDamage);
if ( bIncDamage )
Monsters[i].FireDamageClass = DamType;
else
Monsters[i].FireDamageClass = class'DamTypeFlamethrower';
}
Monsters[i].Instigator = instigatedBy;
Monsters[i].TotalInputDamage += Damage;
Victim.BurnDown = Monsters[i].BurnDown;
Victim.TakeDamage(Damage, instigatedBy, hitLocation, momentum, DamType, HitIndex);
if ( Victim.Health <= 0 )
StopBurningBehavior(Victim);
else if ( FlareDamType != none )
FlareMonster(i);
return;
}
}
// If we've reached here, zed isn't burning yet.
// First we need to check if zed can be set on fire, otherwise don't apply burning mechanism
// on it (e.g. some Doom3 monsters are immune to fire).
if ( FlareDamType != none ) {
Victim.HeatAmount = 5; // just to be sure this gay feature don't block zed's ignition
}
OldHealth = Victim.Health;
//damage zed and check if it's burning
Victim.TakeDamage(Damage, instigatedBy, hitLocation, momentum, DamType, HitIndex);
if ( bOutputDamage && InstigatedBy != none && PlayerController(InstigatedBy.Controller) != none )
PlayerController(InstigatedBy.Controller).ClientMessage(
"Initial Damage: " $ Damage $ "/" $ String(OldHealth - Victim.Health)
@ " -> "@ Victim.MenuName);
//store burned damage in this variable. It is of Byte type, so can't write big values into it
//Victim.HeatAmount = min(127, Victim.HeatAmount + OldHealth - Victim.Health);
if ( !Victim.bBurnified && Victim.BurnDown == 0 )
return; // can't be set on fire
if ( Victim.Health <= 0 ) {
StopBurningBehavior(Victim);
return;
}
// if we reached here, zed is ignited and should burning - OUR WAY
// KFMonster.Timer() makes fire damage based on LastBurnDamage + 3 + rand(2)
// if player is lucky, monster will take another +1 damage per tick :)
Victim.SetTimer(0, false); //disable timer, cuz we'll be using our own
Victim.LastBurnDamage = -3;
Victim.BurnDown = BurnDuration;
//add new record
i = FreeSlot;
if ( i == Monsters.Length ) {
Monsters.insert( i, 1 );
}
Monsters[i].Victim = Victim;
Monsters[i].Instigator = InstigatedBy;
Monsters[i].NextBurnTime = Level.TimeSeconds + BurnPeriod;
Monsters[i].BurnTicks = 0;
Monsters[i].BurnDamage = Damage;
Monsters[i].TotalInputDamage = Damage;
if ( FlareDamType != none ) {
Monsters[i].FireDamageClass = FlareDamType;
Monsters[i].BurnDown = FlareDamType.default.MinBurnTime;
Monsters[i].FlareCount = 1;
FlareMonster(i);
}
else {
if ( bIncDamage )
Monsters[i].FireDamageClass = DamType;
else
Monsters[i].FireDamageClass = class'DamTypeFlamethrower';
Monsters[i].BurnDown = BurnDuration;
Monsters[i].FlareCount = 0;
}
if ( !bTimerLoop ) {
SetTimer(0.1, true);
}
}
function Timer()
{
local int i, EmptyTailBegin;
local int OldHealth;
local int Damage;
local KFMonster M;
if ( Monsters.Length == 0 ) {
SetTimer(0, false);
return;
}
EmptyTailBegin = Monsters.Length;
for ( i = 0; i < Monsters.Length; ++i ) {
if ( Monsters[i].Victim != none && Monsters[i].Victim.Health <= 0 ) {
StopBurningBehavior(Monsters[i].Victim);
Monsters[i].Victim = none;
}
if ( Monsters[i].Victim == none ) {
if ( EmptyTailBegin == Monsters.Length ) {
EmptyTailBegin = i;
}
continue;
}
EmptyTailBegin = Monsters.Length;
M = Monsters[i].Victim;
M.SetTimer(0, false); // ensure that timer is disabled
if ( Monsters[i].NextBurnTime < Level.TimeSeconds ) {
M.bSTUNNED = false; // manualy remove flinching effect here, cuz we disabled the timer
M.BurnDown = max(Monsters[i].BurnDown, 2); //can't be less, or TakeFireDamage() will decrease it to 0 and turn off burning
if ( Monsters[i].FlareCount > 0 )
Damage = Monsters[i].BurnDamage; // flares don't use burn in
else
Damage = GetAvgBurnDamage(Monsters[i].BurnDown, Monsters[i].BurnDamage);
OldHealth = Monsters[i].Victim.Health;
M.TakeDamage(Damage*BurnPeriod, Monsters[i].Instigator, M.Location,
vect(0, 0, 0), Monsters[i].FireDamageClass);
M.LastBurnDamage = -3; //reset to default
if ( bOutputDamage && Monsters[i].Instigator != none && PlayerController(Monsters[i].Instigator.Controller) != none)
PlayerController(Monsters[i].Instigator.Controller).ClientMessage(
"Fire DoT: " $ String(Damage)$ "/" $ String(OldHealth - M.Health)
@ " -> "@ M.MenuName @ "("$String(i+1)$"/"$Monsters.Length$"). Burns = " $ String(Monsters[i].BurnDown)
);
Monsters[i].BurnDown--;
Monsters[i].BurnTicks++;
Monsters[i].NextBurnTime += BurnPeriod;
if ( Monsters[i].FlareCount == 0 && Monsters[i].BurnTicks * BurnPeriod > 10 - M.CrispUpThreshhold )
M.ZombieCrispUp(); // Melt em' :)
if ( M.Health <= 0 ) {
Monsters[i].Victim = none;
StopBurningBehavior(M);
}
else if ( Monsters[i].BurnDown <= 0 ) {
Monsters[i].Victim = none;
if ( FindMonsterIndex(M) == -1 ) {
StopBurningBehavior(M);
}
else if ( Monsters[i].FlareCount > 0 ) {
StopFlareFX(M); // flares burned down, but other burning continues
}
}
}
}
if ( EmptyTailBegin != Monsters.Length ) {
// Remove empty records from the end of the monsters array.
// Shouldn't do it in the middle of array to prevent record shifts in memory.
Monsters.Length = EmptyTailBegin;
}
}
defaultproperties
{
BurnDuration=8
BurnInCount=2
BurnPeriod=1.000000
FlareSoundRef="KF_IJC_HalloweenSnd.KF_FlarePistol_Projectile_Loop"
}

View file

@ -0,0 +1,501 @@
/*
* List of Player's inventory
*/
class ScrnBuyMenuInvList extends SRKFBuyMenuInvList;
var localized string UpgradeArmorCaption;
var localized string NoWeightCaption;
// all update checks now are perfomed in ScrnTab_BuyMenu
function Timer()
{
SetTimer(0, false);
}
function UpdateList()
{
local int i;
local ClientPerkRepLink KFLR;
KFLR = Class'ScrnClientPerkRepLink'.Static.FindMe(PlayerOwner());
if ( MyBuyables.Length < 1 )
{
bNeedsUpdate = true;
return;
}
// Clear the arrays
NameStrings.Remove(0, NameStrings.Length);
AmmoStrings.Remove(0, AmmoStrings.Length);
ClipPriceStrings.Remove(0, ClipPriceStrings.Length);
FillPriceStrings.Remove(0, FillPriceStrings.Length);
PerkTextures.Remove(0, PerkTextures.Length);
// Update the ItemCount and select the first item
ItemCount = MyBuyables.Length;
// Update the players inventory list
for ( i = 0; i < ItemCount; i++ )
{
if ( MyBuyables[i] == none )
continue;
NameStrings[i] = MyBuyables[i].ItemName;
if ( !MyBuyables[i].bIsVest )
{
AmmoStrings[i] = int(MyBuyables[i].ItemAmmoCurrent)$"/"$int(MyBuyables[i].ItemAmmoMax);
if ( MyBuyables[i].ItemAmmoCurrent < MyBuyables[i].ItemAmmoMax )
{
if ( MyBuyables[i].ItemAmmoCost > MyBuyables[i].ItemFillAmmoCost )
{
ClipPriceStrings[i] = class'ScrnUnicode'.default.Dosh @ int(MyBuyables[i].ItemFillAmmoCost);
}
else
{
ClipPriceStrings[i] = class'ScrnUnicode'.default.Dosh @ int(MyBuyables[i].ItemAmmoCost);
}
}
else
{
ClipPriceStrings[i] = class'ScrnUnicode'.default.Dosh @ "0";
}
FillPriceStrings[i] = class'ScrnUnicode'.default.Dosh @ int(MyBuyables[i].ItemFillAmmoCost);
}
else
{
AmmoStrings[i] = int(MyBuyables[i].ItemAmmoCurrent)$"%";
if ( MyBuyables[i].ItemAmmoCurrent == 0 ) {
FillPriceStrings[i] = BuyString @ ": " $ class'ScrnUnicode'.default.Dosh @ int(MyBuyables[i].ItemFillAmmoCost);
}
else if ( MyBuyables[i].ItemAmmoCurrent >= MyBuyables[i].ItemAmmoMax ) {
//if ( MyBuyables[i].ItemAmmoCurrent <= 25 )
// FillPriceStrings[i] = NoWeightCaption;
//else
FillPriceStrings[i] = PurchasedString;
}
else {
FillPriceStrings[i] = RepairString @ ": " $ class'ScrnUnicode'.default.Dosh @ int(MyBuyables[i].ItemFillAmmoCost);
}
}
if( KFLR!=None && KFLR.ShopPerkIcons.Length>MyBuyables[i].ItemPerkIndex )
PerkTextures[i] = Texture(KFLR.ShopPerkIcons[MyBuyables[i].ItemPerkIndex]);
}
if ( bNotify )
CheckLinkedObjects(Self);
if ( MyScrollBar != none )
MyScrollBar.AlignThumb();
bNeedsUpdate = false;
}
// update ammo values of the current list
function UpdateMyAmmo()
{
local GUIBuyable MyBuyable;
local class<ScrnHumanPawn> ScrnPawnClass;
local Ammunition MyAmmo;
local int ClipSize;
local float ClipPrice, FullRefillPrice;
local int i;
ScrnPawnClass = class<ScrnHumanPawn>(PlayerOwner().Pawn.class);
if ( ScrnPawnClass == none )
ScrnPawnClass = class'ScrnBalanceSrv.ScrnHumanPawn';
AutoFillCost = 0;
for ( i = 0; i < MyBuyables.Length; i++ ) {
MyBuyable = MyBuyables[i];
if ( MyBuyable == none || MyBuyable.ItemAmmoClass == none )
continue;
if ( ScrnPawnClass.static.CalcAmmoCost(PlayerOwner().Pawn, MyBuyable.ItemAmmoClass,
MyAmmo, ClipPrice, FullRefillPrice, ClipSize) )
{
MyBuyable.ItemAmmoCost = ceil(ClipPrice);
MyBuyable.ItemFillAmmoCost = ceil(FullRefillPrice);
MyBuyable.ItemAmmoCurrent = MyAmmo.AmmoAmount;
}
AutoFillCost += MyBuyable.ItemAmmoCost;
}
UpdateList();
}
function UpdateMyBuyables()
{
local GUIBuyable MyBuyable, KnifeBuyable, FragBuyable;
local Inventory CurInv;
local float CurAmmo, MaxAmmo;
local class<KFWeaponPickup> MyPickup,MyPrimaryPickup;
local class<ScrnVeterancyTypes> Perk;
local ClientPerkRepLink KFLR;
local KFPlayerReplicationInfo KFPRI;
local float DualCoef; //if replaceable gun's price is different than 2x like in standard dualies
local class<Grenade> NadeType;
local Ammunition MyAmmo;
local float ClipPrice, FullRefillPrice;
local int ClipSize;
local ScrnHumanPawn ScrnPawn;
local class<ScrnHumanPawn> ScrnPawnClass;
// vars below are used in vest price calculation
local float Price1p;
local int Cost, AmountToBuy;
local class<ScrnVestPickup> VestClass;
KFPRI = KFPlayerReplicationInfo(PlayerOwner().PlayerReplicationInfo);
KFLR = Class'ScrnClientPerkRepLink'.Static.FindMe(PlayerOwner());
if( KFLR==None || KFPRI==None )
return; // Hmmmm?
// Let's start with our current inventory
if ( PlayerOwner().Pawn.Inventory == none )
{
log("Inventory is none!");
return;
}
DualCoef = 1;
AutoFillCost = 0.00000;
//Clear the MyBuyables array
CopyAllBuyables();
MyBuyables.Length = 0;
Perk = class<ScrnVeterancyTypes>(KFPRI.ClientVeteranSkill);
if( Perk==None )
Perk = Class'ScrnVeterancyTypes';
ScrnPawn = ScrnHumanPawn(PlayerOwner().Pawn);
if ( ScrnPawn != none )
ScrnPawnClass = ScrnPawn.class;
else
ScrnPawnClass = class'ScrnBalanceSrv.ScrnHumanPawn';
// Fill the Buyables
for ( CurInv = PlayerOwner().Pawn.Inventory; CurInv != none; CurInv = CurInv.Inventory )
{
if ( KFWeapon(CurInv)==None || CurInv.IsA('Welder') || CurInv.IsA('Syringe') )
continue;
// weapons can be derived from another even if they aren't of the same type, e.g. Shotgun -> LAW
// so it's better to compare their pickup classes.
// Doing that will make easier to add custom weapon modification classes
// (c) PooSH, 2012
MyPickup = class<KFWeaponPickup>(CurInv.default.PickupClass);
if ( MyPickup.IsA('DualDeaglePickup') || MyPickup.IsA('Dual44MagnumPickup')
|| MyPickup.IsA('DualMK23Pistol') || MyPickup.IsA('DualFlareRevolver')
|| KFWeapon(CurInv).DemoReplacement!=None ) {
DualCoef = 0.5;
}
else DualCoef = 1;
if ( KFWeapon(CurInv).bHasSecondaryAmmo )
MyPrimaryPickup = MyPickup.default.PrimaryWeaponPickup;
else
MyPrimaryPickup = MyPickup;
MyBuyable = AllocateEntry(KFLR);
KFWeapon(CurInv).GetAmmoCount(MaxAmmo, CurAmmo);
MyBuyable.ItemName = MyPickup.default.ItemShortName;
MyBuyable.ItemDescription= KFWeapon(CurInv).default.Description;
MyBuyable.ItemCategorie = "Melee"; // More dummy.
MyBuyable.ItemImage = KFWeapon(CurInv).default.TraderInfoTexture;
MyBuyable.ItemWeaponClass= KFWeapon(CurInv).class;
MyBuyable.ItemAmmoClass = KFWeapon(CurInv).default.FireModeClass[0].default.AmmoClass;
MyBuyable.ItemPickupClass= MyPrimaryPickup;
MyBuyable.ItemCost = ceil(MyPickup.default.Cost * Perk.static.GetCostScaling(KFPRI, MyPickup) * DualCoef);
// universal method to calculate prices both in trader menu and on server (when actually buying it)
if ( ScrnPawnClass.static.CalcAmmoCost(PlayerOwner().Pawn, MyBuyable.ItemAmmoClass,
MyAmmo, ClipPrice, FullRefillPrice, ClipSize) ) {
MyBuyable.ItemAmmoCost = ceil(ClipPrice);
MyBuyable.ItemFillAmmoCost = ceil(FullRefillPrice);
}
else {
//this never shouldn't happen
MyBuyable.ItemAmmoCost = ceil(MyPrimaryPickup.default.AmmoCost * Perk.static.GetAmmoCostScaling(KFPRI, MyPrimaryPickup) * Perk.static.GetMagCapacityMod(KFPRI, KFWeapon(CurInv)));
MyBuyable.ItemFillAmmoCost = ceil((int(((MaxAmmo - CurAmmo) * float(MyPrimaryPickup.default.AmmoCost)) / float(KFWeapon(CurInv).default.MagCapacity))) * Perk.static.GetAmmoCostScaling(KFPRI, MyPrimaryPickup));
}
MyBuyable.ItemAmmoCurrent= CurAmmo;
MyBuyable.ItemAmmoMax = MaxAmmo;
MyBuyable.ItemWeight = KFWeapon(CurInv).Weight;
MyBuyable.ItemPower = MyPickup.default.PowerValue;
MyBuyable.ItemRange = MyPickup.default.RangeValue;
MyBuyable.ItemSpeed = MyPickup.default.SpeedValue;
// Hack - setting negative ammo cost blocks weapon from refilling ammo in trader
MyBuyable.bMelee = KFWeapon(CurInv).bMeleeWeapon || MyBuyable.ItemAmmoClass==None || MyPickup.default.AmmoCost < 0;
MyBuyable.bSaleList = false;
if ( Perk.static.OverridePerkIndex(MyPickup) )
MyBuyable.ItemPerkIndex = Perk.default.PerkIndex;
else
MyBuyable.ItemPerkIndex = MyPickup.default.CorrespondingPerkIndex;
// Changed from "!= -1" to ">= 0" to prevent possible issues in a future
if ( KFWeapon(CurInv) != none && KFWeapon(CurInv).SellValue >= 0 )
MyBuyable.ItemSellValue = KFWeapon(CurInv).SellValue;
else
MyBuyable.ItemSellValue = MyBuyable.ItemCost * 0.75;
if ( PipeBombExplosive(CurInv) != none ) {
//give 75% of all pipes, not 2 (even if there is only 1 left)
// calc price per ammo and multiply by ammo count
MyBuyable.ItemSellValue /= PipeBombExplosive(CurInv).default.FireModeClass[0].default.AmmoClass.default.InitialAmount;
MyBuyable.ItemSellValue *= PipeBombExplosive(CurInv).AmmoAmount(0);
}
if ( !MyBuyable.bMelee && int(MaxAmmo)>int(CurAmmo) )
AutoFillCost += MyBuyable.ItemFillAmmoCost;
if ( CurInv.IsA('Knife') )
{
MyBuyable.bSellable = false;
KnifeBuyable = MyBuyable;
}
else if ( CurInv.IsA('Frag') )
{
MyBuyable.bSellable = false;
FragBuyable = MyBuyable;
}
else
{
MyBuyable.bSellable = !KFWeapon(CurInv).default.bKFNeverThrow;
MyBuyables.Insert(0,1);
MyBuyables[0] = MyBuyable;
}
// =============================== SECONDARY AMMO ===============================
if ( !KFWeapon(CurInv).bHasSecondaryAmmo )
continue;
// Add secondary ammo.
MyBuyable = AllocateEntry(KFLR);
KFWeapon(CurInv).GetSecondaryAmmoCount(MaxAmmo, CurAmmo);
MyBuyable.ItemName = MyPickup.default.SecondaryAmmoShortName;
MyBuyable.ItemDescription = KFWeapon(CurInv).default.Description;
MyBuyable.ItemCategorie = "Melee";
MyBuyable.ItemImage = KFWeapon(CurInv).default.TraderInfoTexture;
MyBuyable.ItemWeaponClass = KFWeapon(CurInv).class;
MyBuyable.ItemAmmoClass = KFWeapon(CurInv).default.FireModeClass[1].default.AmmoClass;
MyBuyable.ItemPickupClass = MyPickup;
MyBuyable.ItemCost = ceil(MyPickup.default.Cost * Perk.static.GetCostScaling(KFPRI, MyPickup) * DualCoef);
// universal method to calculate prices both in trader menu and on server
if ( ScrnPawnClass.static.CalcAmmoCost(PlayerOwner().Pawn, MyBuyable.ItemAmmoClass,
MyAmmo, ClipPrice, FullRefillPrice, ClipSize) ) {
MyBuyable.ItemAmmoCost = ceil(ClipPrice);
MyBuyable.ItemFillAmmoCost = ceil(FullRefillPrice);
}
else {
//this never shouldn't happen
MyBuyable.ItemAmmoCost = ceil(MyPickup.default.AmmoCost * Perk.static.GetAmmoCostScaling(KFPRI, MyPickup));
MyBuyable.ItemFillAmmoCost = ceil((MaxAmmo - CurAmmo) * float(MyPickup.default.AmmoCost) * Perk.static.GetAmmoCostScaling(KFPRI, MyPrimaryPickup));
}
MyBuyable.ItemAmmoCurrent = CurAmmo;
MyBuyable.ItemAmmoMax = MaxAmmo;
MyBuyable.ItemWeight = KFWeapon(CurInv).Weight;
MyBuyable.ItemPower = MyPickup.default.PowerValue;
MyBuyable.ItemRange = MyPickup.default.RangeValue;
MyBuyable.ItemSpeed = MyPickup.default.SpeedValue;
MyBuyable.bMelee = (KFMeleeGun(CurInv) != none);
MyBuyable.bSaleList = false;
MyBuyable.ItemPerkIndex = MyPickup.default.CorrespondingPerkIndex;
MyBuyable.bSellable = !KFWeapon(CurInv).default.bKFNeverThrow;
if ( KFWeapon(CurInv) != none && KFWeapon(CurInv).SellValue >= 0 )
MyBuyable.ItemSellValue = KFWeapon(CurInv).SellValue;
else
MyBuyable.ItemSellValue = MyBuyable.ItemCost * 0.75;
if ( !MyBuyable.bMelee && int(MaxAmmo) > int(CurAmmo))
AutoFillCost += MyBuyable.ItemFillAmmoCost;
MyBuyables.Insert(1,1);
MyBuyables[1] = MyBuyable;
}
// ARMOR
MyBuyable = AllocateEntry(KFLR);
MyBuyable.ItemCategorie = "";
MyBuyable.ItemAmmoCurrent = PlayerOwner().Pawn.ShieldStrength;
if ( ScrnPawn != none ) {
VestClass = ScrnPawn.GetVestClass();
ScrnPawn.CalcVestCost(VestClass, Cost, AmountToBuy, Price1p);
MyBuyable.ItemName = VestClass.default.ItemShortName;
MyBuyable.ItemDescription = VestClass.default.Description;
MyBuyable.ItemWeight = VestClass.default.Weight;
MyBuyable.ItemImage = VestClass.default.TraderInfoTexture;
MyBuyable.ItemPerkIndex = VestClass.default.CorrespondingPerkIndex;
MyBuyable.ItemAmmoMax = VestClass.default.ShieldCapacity;
MyBuyable.ItemCost = VestClass.default.ShieldCapacity * Price1p;
MyBuyable.ItemAmmoCost = Price1p;
MyBuyable.ItemFillAmmoCost = Cost;
}
else {
MyBuyable.ItemName = class'ScrnBalanceSrv.ScrnVestPickup'.default.ItemShortName;
MyBuyable.ItemDescription = class'ScrnBalanceSrv.ScrnVestPickup'.default.Description;
MyBuyable.ItemWeight = class'ScrnBalanceSrv.ScrnVestPickup'.default.Weight;
MyBuyable.ItemImage = class'BuyableVest'.default.ItemImage;
MyBuyable.ItemPerkIndex = class'BuyableVest'.default.CorrespondingPerkIndex;
MyBuyable.ItemAmmoMax = 100;
MyBuyable.ItemCost = class'BuyableVest'.default.ItemCost
* Perk.static.GetCostScaling(KFPRI, class'Vest')
* MyBuyable.ItemAmmoMax/100.0;
MyBuyable.ItemAmmoCost = MyBuyable.ItemCost / MyBuyable.ItemAmmoMax;
MyBuyable.ItemFillAmmoCost = int((MyBuyable.ItemAmmoMax - MyBuyable.ItemAmmoCurrent) * MyBuyable.ItemAmmoCost);
}
MyBuyable.bIsVest = true;
MyBuyable.bMelee = false;
MyBuyable.bSaleList = false;
MyBuyable.bSellable = false;
// set nade icon corresponding to its type
if ( FragBuyable != none ) {
NadeType = Perk.static.GetNadeType(KFPRI);
if ( NadeType == class'Nade' || NadeType == class'ScrnNade' )
FragBuyable.ItemPerkIndex = 6; // set demo icon by default
else
FragBuyable.ItemPerkIndex = Perk.default.PerkIndex;
}
if( MyBuyables.Length<8 )
{
MyBuyables.Length = 11;
MyBuyables[7] = none;
MyBuyables[8] = KnifeBuyable;
MyBuyables[9] = FragBuyable;
MyBuyables[10] = MyBuyable; // ARMOR
}
else
{
MyBuyables.insert(MyBuyables.Length, 3);
MyBuyables[MyBuyables.Length-3] = none;
MyBuyables[MyBuyables.Length-2] = FragBuyable;
MyBuyables[MyBuyables.Length-1] = MyBuyable; // ARMOR
}
//Now Update the list
UpdateList();
}
function BuyClips(byte ClipAmount)
{
local GUIBuyable Buyable;
local class<Ammunition> MyAmmo;
if ( Index < 0 || Index >= MyBuyables.Length )
return;
Buyable = MyBuyables[Index];
if ( Buyable == none || Buyable.bIsVest || Buyable.bMelee)
return;
// Buyable list is completely rebuilding after each clip purchase.
// Yes, that's lazy and lame. But I think it is impossible to teach
// code optimization to a game developers, who are always orienting
// on high-end computer hardware.
//
// Anyway - we need to be sure that after list rebuilding index is
// pointing on the same ammo as we just bough
MyAmmo = Buyable.ItemAmmoClass;
while ( ClipAmount > 0 && Buyable != none
&& Buyable.ItemAmmoClass == MyAmmo && Buyable.ItemAmmoCurrent < Buyable.ItemAmmoMax )
{
OnBuyClipClick(Buyable);
Buyable = MyBuyables[Index];
ClipAmount--;
}
}
function bool InternalOnClick(GUIComponent Sender)
{
local int NewIndex;
local float RelativeMouseX;
if ( IsInClientBounds() )
{
// Figure out which Item we're clicking on
NewIndex = CalculateIndex();
RelativeMouseX = Controller.MouseX - ClientBounds[0];
if ( RelativeMouseX < ActualWidth() * ItemBGWidthScale )
{
SetIndex(NewIndex);
MouseOverXIndex = 0;
return true;
}
else
{
RelativeMouseX -= ActualWidth() * (ItemBGWidthScale + AmmoBGWidthScale);
if ( RelativeMouseX > 0 )
{
if ( MyBuyables[NewIndex].bIsVest )
{
if ( (PlayerOwner().Pawn.ShieldStrength > 0 && PlayerOwner().PlayerReplicationInfo.Score >= MyBuyables[NewIndex].ItemAmmoCost) || PlayerOwner().PlayerReplicationInfo.Score >= MyBuyables[NewIndex].ItemCost )
OnBuyVestClick();
}
else if ( !MyBuyables[NewIndex].bMelee )
{
if ( RelativeMouseX < ActualWidth() * (1.0 - ItemBGWidthScale - AmmoBGWidthScale) * ClipButtonWidthScale )
OnBuyClipClick(MyBuyables[NewIndex]); // Buy Clip
else
OnFillAmmoClick(MyBuyables[NewIndex]); // Fill Ammo
}
}
}
}
return false;
}
function bool InternalOnKeyEvent(out byte Key, out byte State, float delta)
{
if ( State == 1 ) { // key press
if (Key >= 0x30 && Key <= 0x39) { // 0..9
Controller.PlayInterfaceSound(CS_Up);
if ( Key == 0x30 )
BuyClips(10);
else
BuyClips(Key - 0x30);
return true;
}
switch (Key) {
case 0x08: // IK_Backspace
OnDblClick(Self); // sell item
return true;
break;
}
}
return super.InternalOnKeyEvent(Key, State, delta);
}
defaultproperties
{
UpgradeArmorCaption="Upgrade"
NoWeightCaption="No Free Weight"
}

View file

@ -0,0 +1,12 @@
class ScrnBuyMenuInvListBox extends SRKFBuyMenuInvListBox;
function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
DefaultListClass=String(class'ScrnBalanceSrv.ScrnBuyMenuInvList');
//bypass SRBuyMenuSaleListBox here
Super(KFBuyMenuInvListBox).InitComponent(MyController,MyOwner);
}
defaultproperties
{
}

View file

@ -0,0 +1,816 @@
/*
* List of Weapons avaliable for purchase
*/
class ScrnBuyMenuSaleList extends SRBuyMenuSaleList;
var texture ActiveGroupArrowLeft, ActiveGroupArrowRight;
var texture GroupArrowLeft, GroupArrowRight;
var texture GroupBackground;
var Color GroupColor, ActiveGroupColor, SelectedGroupColor;
var bool bMouseOverPrice;
var texture PriceButton, PriceButtonDisabled, PriceButtonSelected;
var Color PriceButtonColor, PriceButtonDisabledColor, PriceButtonSelectedColor;
var float ItemXMargin; //Item margin in % of width
var float PriceButtonWidthScale;
var int InventoryCount;
var texture FavoritesIcon;
var array<localized string> LockStrings;
// all update checks now are perfomed in ScrnTab_BuyMenu
function Timer()
{
SetTimer(0, false);
}
event Opened(GUIComponent Sender)
{
local ScrnHUD myHUD;
super.Opened(Sender);
// load config variables
myHUD = ScrnHUD(PlayerOwner().myHUD);
if ( myHUD != none ) {
GroupColor = myHUD.TraderGroupColor;
ActiveGroupColor = myHUD.TraderActiveGroupColor;
SelectedGroupColor = myHUD.TraderSelectedGroupColor;
PriceButtonColor = myHUD.TraderPriceButtonColor;
PriceButtonDisabledColor = myHUD.TraderPriceButtonDisabledColor;
PriceButtonSelectedColor = myHUD.TraderPriceButtonSelectedColor;
}
}
//returns true also if any children of pickup class are found
function bool IsChildInInventory(class<Pickup> Item)
{
local Inventory CurInv;
for ( CurInv = PlayerOwner().Pawn.Inventory; CurInv != none; CurInv = CurInv.Inventory )
{
if ( ClassIsChildOf(CurInv.default.PickupClass, Item) )
{
return true;
}
}
return false;
}
function UpdateForSaleBuyables()
{
local class<ScrnVeterancyTypes> Perk;
local KFPlayerReplicationInfo KFPRI;
local ScrnClientPerkRepLink CPRL;
local GUIBuyable ForSaleBuyable;
local class<KFWeaponPickup> ForSalePickup;
local int k, j, i, z, Num;
local class<KFWeapon> ForSaleWeapon;
local float DualCoef; //if replaceable gun's price is different than 2x like in standard dualies
local bool bHasDual;
local ScrnHumanPawn ScrnPawn;
local bool bVest;
local int PerkedPos; //position after the last perked buyable to add new inventory there
// vars below are used in vest price calculation
local float Price1p;
local int Cost, AmountToBuy;
//local class<SRVeterancyTypes> Blocker;
local KFShopVolume_Story CurrentShop;
local ScrnBalance Mut;
local byte DLCLocked;
local ScrnGUIBuyWeaponInfoPanel InfoPanel;
local bool bOverridePerkIndex; // use perk index insead if item's index
// Clear the ForSaleBuyables array
CopyAllBuyables();
ForSaleBuyables.Length = 0;
Mut = class'ScrnBalance'.static.Myself(PlayerOwner().Level);
// Grab the items for sale
CPRL = Class'ScrnClientPerkRepLink'.Static.FindMe(PlayerOwner());
if( CPRL==None )
return; // Hmmmm?
if ( ScrnTab_BuyMenu(MenuOwner.MenuOwner) != none )
InfoPanel = ScrnGUIBuyWeaponInfoPanel(ScrnTab_BuyMenu(MenuOwner.MenuOwner).ItemInfo);
// Grab Players Veterancy for quick reference
KFPRI = KFPlayerReplicationInfo(PlayerOwner().PlayerReplicationInfo);
if ( KFPRI != none )
Perk = class<ScrnVeterancyTypes>(KFPRI.ClientVeteranSkill);
if( Perk==None )
Perk = class'ScrnVeterancyTypes';
CurrentShop = GetCurrentShop();
ScrnPawn = ScrnHumanPawn(PlayerOwner().Pawn);
if( ActiveCategory>=-1 )
{
// Grab the weapons!
if( CurrentShop!=None )
Num = CurrentShop.SaleItems.Length;
else
Num = CPRL.ShopInventory.Length;
for ( z=0; z<Num; z++ ) {
//reset variables
DualCoef = 1;
bHasDual = false;
// Use Story Mode shop, if defined, otherwise use classic level rules
if( CurrentShop!=None )
{
// Allow story mode volume limit weapon availability.
ForSalePickup = class<KFWeaponPickup>(CurrentShop.SaleItems[z]);
if( ForSalePickup==None )
continue;
for ( j=(CPRL.ShopInventory.Length-1); j>=CPRL.ShopInventory.Length; --j )
if( CPRL.ShopInventory[j].PC==ForSalePickup )
break;
if( j<0 )
continue;
}
else
{
ForSalePickup = class<KFWeaponPickup>(CPRL.ShopInventory[z].PC);
j = z;
}
if ( ForSalePickup==None || IsInInventory(ForSalePickup) )
continue;
bOverridePerkIndex = Perk.static.OverridePerkIndex(ForSalePickup);
if ( class'ScrnBalance'.default.Mut.bBuyPerkedWeaponsOnly
&& !bOverridePerkIndex
&& ForSalePickup.default.CorrespondingPerkIndex != Perk.default.PerkIndex
&& ForSalePickup.default.CorrespondingPerkIndex != 7 ) // off-perk
continue;
if( ActiveCategory==-1 )
{
if( !Class'SRClientSettings'.Static.IsFavorite(ForSalePickup) )
continue; // not favorite
// check for duplicates
for ( k=0; k < ForSaleBuyables.length; ++k ) {
if ( ForSaleBuyables[k].ItemPickupClass == ForSalePickup )
break;
}
if ( k < ForSaleBuyables.length )
continue; // ForSalePickup is already inside ForSaleBuyables
}
else if( ActiveCategory!=CPRL.ShopInventory[j].CatNum )
continue;
ForSaleWeapon = class<KFWeapon>(ForSalePickup.default.InventoryType);
if ( ForSaleWeapon != none && ForSaleWeapon.default.bKFNeverThrow )
continue;
bVest = ClassIsChildOf(ForSalePickup, class'ScrnBalanceSrv.ScrnVestPickup');
if ( bVest ) {
//vest
if ( ScrnPawn == none || class<ScrnVestPickup>(ForSalePickup).default.ShieldCapacity <= 0
|| (ScrnPawn.GetCurrentVestClass() == ForSalePickup && ScrnPawn.ShieldStrength >= ScrnPawn.GetShieldStrengthMax() ) )
continue;
}
else if ( ForSaleWeapon != none ) {
// Remove single weld.
//Scrn pistols are linked through DemoReplacement, so no need to look for chilldren here
if ( (ForSalePickup == class'DeaglePickup' && IsInInventory(class'DualDeaglePickup'))
|| (ForSalePickup == class'Magnum44Pickup' && IsInInventory(class'Dual44MagnumPickup'))
|| (ForSalePickup == class'MK23Pickup' && IsInInventory(class'DualMK23Pickup'))
|| (ForSalePickup == class'FlareRevolverPickup' && IsInInventory(class'DualFlareRevolverPickup'))
|| DualIsInInventory(ForSaleWeapon) )
continue;
// hide single and dual pistols, if player has laser variant
if ( (ForSalePickup == class'Magnum44Pickup' || ForSalePickup == class'ScrnMagnum44Pickup'
|| ForSalePickup == class'Dual44MagnumPickup' || ForSalePickup == class'ScrnDual44MagnumPickup')
&& IsInInventory(class'ScrnDual44MagnumLaserPickup') )
continue;
if ( (ForSalePickup == class'MK23Pickup' || ForSalePickup == class'ScrnMK23Pickup'
|| ForSalePickup == class'DualMK23Pickup' || ForSalePickup == class'ScrnDualMK23Pickup')
&& IsInInventory(class'ScrnDualMK23LaserPickup') )
continue;
// Make cheaper.
if ( (ForSalePickup == class'DualDeaglePickup' && IsInInventory(class'DeaglePickup'))
|| (ForSalePickup == class'Dual44MagnumPickup' && IsInInventory(class'Magnum44Pickup'))
|| (ForSalePickup == class'DualMK23Pickup' && IsInInventory(class'MK23Pickup'))
|| (ForSalePickup == class'DualFlareRevolverPickup' && IsInInventory(class'FlareRevolverPickup'))
|| (ForSaleWeapon.Default.DemoReplacement!=None && IsInInventoryWep(ForSaleWeapon.Default.DemoReplacement)) ) {
DualCoef = 0.5;
bHasDual = true;
}
}
// 9.19: removed perk query due to performance reasons
// todo: add better way t
// Blocker = None;
// for( i=0; i<CPRL.CachePerks.Length; ++i )
// if( !CPRL.CachePerks[i].PerkClass.Static.AllowWeaponInTrader(ForSalePickup,KFPRI,CPRL.CachePerks[i].CurrentLevel) )
// {
// Blocker = CPRL.CachePerks[i].PerkClass;
// break;
// }
// if( Blocker!=None && Blocker.Default.DisableTag=="" )
// continue;
ForSaleBuyable = AllocateEntry(CPRL);
ForSaleBuyable.ItemName = ForSalePickup.default.ItemName;
ForSaleBuyable.ItemDescription = ForSalePickup.default.Description;
ForSaleBuyable.ItemCategorie = "Melee"; // Dummy stuff..
ForSaleBuyable.ItemAmmoCost = 0;
ForSaleBuyable.ItemFillAmmoCost = 0;
ForSaleBuyable.ItemPickupClass = ForSalePickup;
ForSaleBuyable.ItemWeaponClass = ForSaleWeapon;
ForSaleBuyable.ItemWeight = ForSalePickup.default.Weight;
if ( bVest ) {
ForSaleBuyable.ItemImage = class<ScrnVestPickup>(ForSalePickup).default.TraderInfoTexture;
ScrnPawn.CalcVestCost(class<ScrnVestPickup>(ForSalePickup), Cost, AmountToBuy, Price1p);
ForSaleBuyable.ItemCost = Cost;
ForSaleBuyable.ItemWeight -= ScrnPawn.GetCurrentVestClass().default.Weight;
}
else {
ForSaleBuyable.ItemCost = int( float(ForSalePickup.default.Cost)
* Perk.static.GetCostScaling(KFPRI, ForSalePickup)
* DualCoef );
if ( ForSaleWeapon != none ) {
ForSaleBuyable.ItemImage = ForSaleWeapon.default.TraderInfoTexture;
ForSaleBuyable.ItemAmmoClass = ForSaleWeapon.default.FireModeClass[0].default.AmmoClass;
ForSaleBuyable.ItemWeight = ForSaleWeapon.default.Weight;
if( bHasDual ) {
if( ForSalePickup == Class'DualDeaglePickup' )
ForSaleBuyable.ItemWeight -= class'Deagle'.default.Weight;
else if( ForSalePickup == class'Dual44MagnumPickup' )
ForSaleBuyable.ItemWeight -= class'Magnum44Pistol'.default.Weight;
else if( ForSalePickup == class'DualMK23Pistol' )
ForSaleBuyable.ItemWeight -= class'MK23Pistol'.default.Weight;
else if( ForSalePickup == class'DualFlareRevolver' )
ForSaleBuyable.ItemWeight -= class'FlareRevolver'.default.Weight;
else ForSaleBuyable.ItemWeight -= Class<KFWeapon>(ForSaleWeapon.Default.DemoReplacement).Default.Weight;
}
}
}
ForSaleBuyable.ItemPower = ForSalePickup.default.PowerValue;
ForSaleBuyable.ItemRange = ForSalePickup.default.RangeValue;
ForSaleBuyable.ItemSpeed = ForSalePickup.default.SpeedValue;
ForSaleBuyable.ItemAmmoCurrent = 0;
ForSaleBuyable.ItemAmmoMax = 0;
if ( bOverridePerkIndex )
ForSaleBuyable.ItemPerkIndex = Perk.default.PerkIndex;
else
ForSaleBuyable.ItemPerkIndex = ForSalePickup.default.CorrespondingPerkIndex;
// Make sure we mark the list as a sale list
ForSaleBuyable.bSaleList = true;
// Sort same perk weapons in front.
if( ForSaleBuyable.ItemPerkIndex == Perk.default.PerkIndex ) {
i = PerkedPos++; // fixed reverse order for perked inventory -- PooSH
}
else {
i = ForSaleBuyables.Length;
}
ForSaleBuyables.Insert(i, 1);
ForSaleBuyables[i] = ForSaleBuyable;
DLCLocked = CPRL.ShopInventory[j].bDLCLocked;
if ( DLCLocked == CPRL.DLC_LOCK_SCRN && CPRL.IsShopInventoryUnlocked(j) )
DLCLocked = 0; // ScrN Lock exists, but it is unlocked atm
else if ( Mut.bBeta && DLCLocked <= 2)
DLCLocked = 0;
// if( DLCLocked==0 && Blocker!=None ) {
// ForSaleBuyable.ItemCategorie = Blocker.Default.DisableTag$":"$Blocker.Default.DisableDescription;
// DLCLocked = 3;
// }
ForSaleBuyable.ItemAmmoCurrent = DLCLocked; // DLC info.
if ( InfoPanel != none ) {
InfoPanel.LoadStats(ForSaleBuyable, 0, true);
InfoPanel.LoadStats(ForSaleBuyable, 1, true);
}
}
}
// Now Update the list
UpdateList();
}
function UpdateList()
{
local int i,j;
local ClientPerkRepLink CPRL;
CPRL = Class'ScrnClientPerkRepLink'.Static.FindMe(PlayerOwner());
// Update the ItemCount and select the first item
ItemCount = CPRL.ShopCategories.Length + ForSaleBuyables.Length + 1;
// Clear the arrays
if ( ForSaleBuyables.Length < PrimaryStrings.Length )
{
PrimaryStrings.Length = ItemCount;
SecondaryStrings.Length = ItemCount;
CanBuys.Length = ItemCount;
ListPerkIcons.Length = ItemCount;
}
// Update categories
if( ActiveCategory>=-1 )
{
for( i=-1; i<(ActiveCategory+1); ++i )
{
if( i==-1 )
{
PrimaryStrings[j] = FavoriteGroupName;
ListPerkIcons[j] = None;
}
else
{
PrimaryStrings[j] = CPRL.ShopCategories[i].Name;
if( CPRL.ShopCategories[i].PerkIndex<CPRL.ShopPerkIcons.Length )
ListPerkIcons[j] = CPRL.ShopPerkIcons[CPRL.ShopCategories[i].PerkIndex];
else ListPerkIcons[j] = None;
}
CanBuys[j] = 3+i;
++j;
}
}
else
{
PrimaryStrings[j] = FavoriteGroupName;
CanBuys[j] = 2;
++j;
for( i=0; i<CPRL.ShopCategories.Length; ++i )
{
PrimaryStrings[j] = CPRL.ShopCategories[i].Name;
if( CPRL.ShopCategories[i].PerkIndex<CPRL.ShopPerkIcons.Length )
ListPerkIcons[j] = CPRL.ShopPerkIcons[CPRL.ShopCategories[i].PerkIndex];
else ListPerkIcons[j] = None;
CanBuys[j] = 3+i;
++j;
}
}
// Update the players inventory list
for ( i=0; i<ForSaleBuyables.Length; i++ )
{
PrimaryStrings[j] = ForSaleBuyables[i].ItemName;
SecondaryStrings[j] = class'ScrnUnicode'.default.Dosh @ int(ForSaleBuyables[i].ItemCost);
if( ForSaleBuyables[i].ItemPerkIndex<CPRL.ShopPerkIcons.Length )
ListPerkIcons[j] = CPRL.ShopPerkIcons[ForSaleBuyables[i].ItemPerkIndex];
else
ListPerkIcons[j] = None;
if( ForSaleBuyables[i].ItemAmmoCurrent > 0 ) {
CanBuys[j] = 0;
if ( ForSaleBuyables[i].ItemAmmoCurrent == 3 )
SecondaryStrings[j] = Left(ForSaleBuyables[i].ItemCategorie,InStr(ForSaleBuyables[i].ItemCategorie,":"));
else
SecondaryStrings[j] = LockStrings[min(ForSaleBuyables[i].ItemAmmoCurrent,LockStrings.Length-1)];
}
else if ( ForSaleBuyables[i].ItemCost > PlayerOwner().PlayerReplicationInfo.Score ||
ForSaleBuyables[i].ItemWeight + KFHumanPawn(PlayerOwner().Pawn).CurrentWeight > KFHumanPawn(PlayerOwner().Pawn).MaxCarryWeight )
{
CanBuys[j] = 0;
}
else
{
CanBuys[j] = 1;
}
++j;
}
if( ActiveCategory>=-1 )
{
for( i=(ActiveCategory+1); i<CPRL.ShopCategories.Length; ++i )
{
PrimaryStrings[j] = CPRL.ShopCategories[i].Name;
if( CPRL.ShopCategories[i].PerkIndex<CPRL.ShopPerkIcons.Length )
ListPerkIcons[j] = CPRL.ShopPerkIcons[CPRL.ShopCategories[i].PerkIndex];
else ListPerkIcons[j] = None;
CanBuys[j] = 3+i;
++j;
}
}
if ( bNotify )
{
CheckLinkedObjects(Self);
}
if ( MyScrollBar != none )
{
MyScrollBar.AlignThumb();
}
bNeedsUpdate = false;
}
// function bool PreDraw(Canvas Canvas)
// {
// local result;
// result = super.PreDraw(Canvas);
// bMouseOverPrice = IsMouseOverPrice();
// return result;
// }
function DrawInvItem(Canvas Canvas, int CurIndex, float X, float Y, float Width, float Height, bool bSelected, bool bPending)
{
local float TempX, TempY, TempHeight, TempWidth, IconSize;
local float PriceLeft, PriceWidth;
local float StringHeight, StringWidth;
// local ClientPerkRepLink CPRL;
local Material M, M2;
local Color OriginalColor;
local bool bGroup, bActiveGroup, bDisabled;
OnClickSound = CS_Click;
// Offset for the Background
TempX = X;
TempY = Y;
TempHeight = Height - ItemSpacing;
TempWidth = Width;
// Initialize the Canvas
Canvas.Style = 1;
//Canvas.Font = class'ROHUD'.Static.GetSmallMenuFont(Canvas);
Canvas.SetDrawColor(255, 255, 255, 255);
OriginalColor = Canvas.DrawColor;
bGroup = CanBuys[CurIndex] > 1;
bActiveGroup = bGroup && (ActiveCategory == CanBuys[CurIndex] - 3);
bDisabled = CanBuys[CurIndex] == 0;
if ( bGroup ) {
// CATEGORY
TempY += Height - TempHeight; // allign bottom
IconSize = TempHeight - 4;
// Background
if ( bSelected )
Canvas.DrawColor = SelectedGroupColor;
else if ( bActiveGroup )
Canvas.DrawColor = ActiveGroupColor;
else
Canvas.DrawColor = GroupColor;
Canvas.SetPos(TempX, TempY);
Canvas.DrawTileStretched(GroupBackground, TempWidth, TempHeight);
Canvas.DrawColor = OriginalColor;
// tree arrow
Canvas.SetDrawColor(255, 255, 255, 128);
Canvas.SetPos(TempX + 4, TempY + 2);
if ( bActiveGroup ) {
M = ActiveGroupArrowLeft;
M2 = ActiveGroupArrowRight;
}
else {
M = GroupArrowLeft;
M2 = GroupArrowRight;
}
Canvas.SetPos(TempX, TempY);
Canvas.DrawTile(M, IconSize, IconSize, 0, 0, M.MaterialUSize(), M.MaterialVSize());
Canvas.SetPos(TempX + TempWidth - IconSize - 4, TempY);
Canvas.DrawTile(M2, IconSize, IconSize, 0, 0, M.MaterialUSize(), M.MaterialVSize());
Canvas.DrawColor = OriginalColor;
// category name
if ( CurIndex == MouseOverIndex )
Canvas.SetDrawColor(255, 255, 255, 255);
else
Canvas.SetDrawColor(0, 0, 0, 255);
Canvas.StrLen(PrimaryStrings[CurIndex], StringWidth, StringHeight);
Canvas.SetPos( TempX + (TempWidth - StringWidth)/2, TempY + ((TempHeight - StringHeight) / 2)); // HCenter
Canvas.DrawText(PrimaryStrings[CurIndex]);
// perk icon
if ( CanBuys[CurIndex] == 2 )
M = FavoritesIcon;
else
M = ListPerkIcons[CurIndex];
if( M != None ) {
Canvas.SetDrawColor(255, 255, 255, 255);
Canvas.SetPos( TempX + (TempWidth - StringWidth)/2 - IconSize - 8, TempY + ((TempHeight - IconSize) / 2)); // HCenter
Canvas.DrawTile(M, IconSize, IconSize, 0, 0, M.MaterialUSize(), M.MaterialVSize());
Canvas.SetPos( TempX + (TempWidth + StringWidth)/2 + 8, TempY + ((TempHeight - IconSize) / 2)); // HCenter
Canvas.DrawTile(M, IconSize, IconSize, 0, 0, M.MaterialUSize(), M.MaterialVSize());
}
}
else {
// ITEM
TempHeight += ItemSpacing/2; // less spacing between items
TempY = Y; // align top
TempWidth *= 1.0 - 2.0*ItemXMargin;
IconSize = TempHeight - 4;
// Background
PriceWidth = Width * PriceButtonWidthScale;
PriceLeft = TempX + TempWidth - PriceWidth;
if ( bDisabled ) {
M = DisabledItemBackgroundLeft;
M2 = DisabledItemBackgroundRight;
}
else if ( bSelected ) {
M = SelectedItemBackgroundLeft;
M2 = SelectedItemBackgroundRight;
}
else {
M = ItemBackgroundLeft;
M2 = ItemBackgroundRight;
}
TempX = X + Width*ItemXMargin;
Canvas.SetPos(TempX, TempY);
Canvas.DrawTileStretched(M, TempHeight, TempHeight);
Canvas.SetPos(TempX + TempHeight, TempY);
Canvas.DrawTileStretched(M2, PriceLeft - TempX - TempHeight - 2, TempHeight);
// price button
if ( bDisabled ) {
M = PriceButtonDisabled;
Canvas.DrawColor = PriceButtonDisabledColor;
}
else if ( CurIndex == MouseOverIndex && IsMouseOverPrice() ) {
M = PriceButtonSelected;
Canvas.DrawColor = PriceButtonSelectedColor;
}
else {
M = PriceButton;
Canvas.DrawColor = PriceButtonColor;
}
Canvas.SetPos(PriceLeft, TempY);
Canvas.DrawTileStretched(M, PriceWidth, TempHeight);
M = ListPerkIcons[CurIndex];
if ( M == None )
M = NoPerkIcon;
// v7
if( M != None ) {
Canvas.SetDrawColor(255, 255, 255, 255);
Canvas.SetPos(TempX + 2, TempY + 2);
Canvas.DrawTile(M, IconSize, IconSize, 0, 0, M.MaterialUSize(), M.MaterialVSize());
}
// item name
if ( bDisabled && bSelected )
Canvas.SetDrawColor(255, 0, 0, 255);
else if ( CurIndex == MouseOverIndex )
Canvas.SetDrawColor(255, 255, 255, 255);
else
Canvas.SetDrawColor(0, 0, 0, 255);
Canvas.StrLen(PrimaryStrings[CurIndex], StringWidth, StringHeight);
Canvas.SetPos(TempX + IconSize + 10, TempY + (TempHeight - StringHeight)/2);
Canvas.DrawText(PrimaryStrings[CurIndex]);
// item price
if ( bDisabled && !bSelected && SecondaryStrings[CurIndex] == LockStrings[5] )
Canvas.SetDrawColor(200, 100, 0, 255);
Canvas.StrLen(SecondaryStrings[CurIndex], StringWidth, StringHeight);
Canvas.SetPos(PriceLeft + (PriceWidth - StringWidth)/2, TempY + (TempHeight - StringHeight)/2);
Canvas.DrawText(SecondaryStrings[CurIndex]);
}
Canvas.DrawColor = OriginalColor;
}
function float SaleItemHeight(Canvas c)
{
return (MenuOwner.ActualHeight() / ItemsPerPage - 1);
}
function bool GotoNextCategory()
{
local int i;
for ( i=Index+1; i<CanBuys.length; ++i ) {
if ( CanBuys[i] > 1 ) {
SetIndex(i);
return true;
}
}
return false;
}
function bool GotoPrevCategory()
{
local int i;
for ( i=Index-1; i>=0; --i ) {
if ( CanBuys[i] > 1 ) {
SetIndex(i);
return true;
}
}
return false;
}
function bool GotoNextItemInCategory()
{
local int i;
// special case when navigating from the very last item in the list
if ( Index == CanBuys.length - 1 && CanBuys[Index] < 2)
return GotoFirstItemInCategory();
for ( i=Index+1; i<CanBuys.length; ++i ) {
if ( CanBuys[i] == 1 ) {
SetIndex(i);
return true;
}
else if ( CanBuys[i] >= 2 )
return GotoFirstItemInCategory();
}
return false;
}
function bool GotoPrevItemInCategory()
{
local int i;
for ( i=Index-1; i>=0; --i ) {
if ( CanBuys[i] == 1 ) {
SetIndex(i);
return true;
}
else if ( CanBuys[i] >= 2 )
return GotoLastItemInCategory();
}
return false;
}
function bool GotoLastItemInCategory()
{
local int i;
for ( i=CanBuys.length-1; i>=0; --i ) {
if ( CanBuys[i] == 1 ) {
SetIndex(i);
return true;
}
}
return false;
}
function bool GotoFirstItemInCategory()
{
local int i;
for ( i=0; i<CanBuys.length; ++i ) {
if ( CanBuys[i] == 1 ) {
SetIndex(i);
return true;
}
}
return false;
}
function bool InternalOnKeyEvent(out byte Key, out byte State, float delta)
{
if ( State == 1 ) { // key press
if (Key >= 0x30 && Key <= 0x39) { // 0..9
SetCategoryNum(Key - 0x31);
return true;
}
switch (Key) {
case 13: // enter
if ( CanBuys[Index] > 1 )
SetCategoryNum(CanBuys[Index] - 3 ); // open/close group
else
OnDblClick(Self); // buy item
return true;
break;
case 33: // page up
if ( GotoPrevCategory() )
SetCategoryNum(CanBuys[Index] - 3 );
return true;
break;
case 34: // page down
if ( GotoNextCategory() )
SetCategoryNum(CanBuys[Index] - 3 );
return true;
break;
case 35: // end
if ( ItemCount > 0 ) {
if ( ActiveCategory == -2)
SetIndex(ItemCount-1);
else
GotoLastItemInCategory();
}
return true;
break;
case 36: // home
if ( ActiveCategory == -2)
SetIndex(0);
else
GotoFirstItemInCategory();
return true;
break;
case 37: // left
if ( ActiveCategory > -2 )
SetCategoryNum(ActiveCategory);
return true;
break;
case 38: // up
if ( ActiveCategory >= -1 ) {
// if category is open - navigate only through its items
// overwise - navigate through categories (native implementation)
GotoPrevItemInCategory();
return true;
}
break;
case 39: // right
if ( ActiveCategory == -2 && CanBuys[Index] > 1 )
SetCategoryNum(CanBuys[Index] - 3 );
return true;
break;
case 40: // down
if ( ActiveCategory >= -1 ) {
// if category is open - navigate only through its items
// overwise - navigate through categories (native implementation)
GotoNextItemInCategory();
return true;
}
break;
}
}
return super.InternalOnKeyEvent(Key, State, delta);
}
function bool IsMouseOverPrice()
{
local float RelativeMouseX;
RelativeMouseX = Controller.MouseX - ClientBounds[0];
return RelativeMouseX >= ActualWidth() * (1.0 - PriceButtonWidthScale - ItemXMargin)
&& RelativeMouseX < ActualWidth() * (1.0 - ItemXMargin);
}
function bool InternalOnClick(GUIComponent Sender)
{
local int NewIndex;
if ( IsInClientBounds() && CanBuys.length > 0 ) {
// Figure out which Item we're clicking on
NewIndex = CalculateIndex();
if ( NewIndex == -1 )
return true;
SetIndex(NewIndex);
if ( CanBuys[NewIndex] >= 2 )
SetCategoryNum(CanBuys[NewIndex] - 3 ); // clicked on group
else if (IsMouseOverPrice())
OnDblClick(Self); // buy item
}
return true;
}
defaultproperties
{
ActiveGroupArrowLeft=Texture'KF_InterfaceArt_tex.Menu.DownMark'
ActiveGroupArrowRight=Texture'KF_InterfaceArt_tex.Menu.DownMark'
GroupArrowLeft=Texture'KF_InterfaceArt_tex.Menu.RightMark'
GroupArrowRight=Texture'KF_InterfaceArt_tex.Menu.LeftMark'
GroupBackground=Texture'KF_InterfaceArt_tex.Menu.Button'
GroupColor=(B=128,G=128,R=128,A=255)
ActiveGroupColor=(B=255,G=192,R=192,A=255)
SelectedGroupColor=(B=255,G=192,R=192,A=255)
PriceButton=Texture'KF_InterfaceArt_tex.Menu.Button'
PriceButtonDisabled=Texture'KF_InterfaceArt_tex.Menu.button_Disabled'
PriceButtonSelected=Texture'KF_InterfaceArt_tex.Menu.Button'
PriceButtonColor=(B=160,G=160,R=160,A=255)
PriceButtonDisabledColor=(B=255,G=255,R=255,A=255)
PriceButtonSelectedColor=(B=160,G=128,R=255,A=255)
ItemXMargin=0.010000
PriceButtonWidthScale=0.200000
FavoritesIcon=Texture'KillingFloor2HUD.Perk_Icons.Favorite_Perk_Icon'
LockStrings(1)="DLC"
LockStrings(2)="LOCKED"
LockStrings(3)="PERK?"
LockStrings(4)="SP?"
LockStrings(5)="ACH"
LockStrings(6)="???"
ItemSpacing=8.000000
ItemsPerPage=14
}

View file

@ -0,0 +1,12 @@
class ScrnBuyMenuSaleListBox extends SRBuyMenuSaleListBox;
function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
DefaultListClass=string(Class'ScrnBuyMenuSaleList');
//bypass SRBuyMenuSaleListBox here
Super(KFBuyMenuSaleListBox).InitComponent(MyController,MyOwner);
}
defaultproperties
{
}

View file

@ -0,0 +1,70 @@
class ScrnCashPickup extends CashPickup;
var() protected float FadeOutTime;
var() bool bAutoFadeOutTime;
function float GetFadeOutTime()
{
return FadeOutTime;
}
function SetFadeOutTime(float value)
{
FadeOutTime = value;
LifeSpan = FadeOutTime + 2;
}
function CalcFadeOutTime()
{
if ( CashAmount < 10 )
FadeOutTime = 8; // default
else if ( CashAmount < 50 )
FadeOutTime = 15;
else
FadeOutTime = 120;
SetFadeOutTime(FadeOutTime);
}
auto state Pickup
{
function BeginState()
{
UntriggerEvent(Event, self, None);
if ( bDropped )
{
AddToNavigation();
SetFadeOutTime(FadeOutTime);
}
}
function SetFadeOutTime(float value)
{
global.SetFadeOutTime(value);
SetTimer(FadeOutTime, false);
}
}
state FallingPickup
{
function BeginState()
{
if ( bAutoFadeOutTime )
CalcFadeOutTime();
else
SetFadeOutTime(FadeOutTime);
}
function SetFadeOutTime(float value)
{
global.SetFadeOutTime(value);
SetTimer(FadeOutTime, false);
}
}
defaultproperties
{
FadeOutTime=8.000000
bAutoFadeOutTime=True
}

View file

@ -0,0 +1,359 @@
class ScrnChainsaw extends Chainsaw;
var float IdleFuelConsumeTime; // time between fuel consumption on idle
var sound EngineStartSound, EngineStopSound;
var string EngineStartSoundRef, EngineStopSoundRef;
struct SoundList {
var string SoundRef;
var sound Sound;
var float Duration;
};
var array<SoundList> ReloadSounds;
var float TotalReloadSoundDuration; // total duration of all reload sounds
var transient float TimeToNextReloadSound;
var transient int NextReloadSoundIndex;
var transient bool bBlownUpThisReload;
var transient int OldMagAmmoRemaining;
var ScrnFakedProjectile FakedGasCan; //adds a faked gas can during reload
replication
{
reliable if(Role == ROLE_Authority)
HideGasCan;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if ( Role < ROLE_Authority ) {
if ( OldMagAmmoRemaining != MagAmmoRemaining ) {
if ( MagAmmoRemaining == 0 ) {
if ( ThirdPersonActor != none )
ThirdPersonActor.AmbientSound = none;
TexPanner(Skins[1]).PanRate = 0; // stop saw cycling
PlaySound(EngineStopSound);
}
else if ( OldMagAmmoRemaining < MagAmmoRemaining && MagAmmoRemaining > 0 ) {
//just reloaded
if ( IsInState('Reloading') )
GotoState('');
if ( ThirdPersonActor != none )
ThirdPersonActor.AmbientSound = ThirdPersonActor.default.AmbientSound;
TexPanner(Skins[1]).PanRate = 3; // start saw cycling
PlaySound(EngineStartSound);
if ( !IsAnimating() )
PlayIdle();
}
OldMagAmmoRemaining = MagAmmoRemaining;
}
}
}
static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount)
{
local int i;
local ScrnChainsaw W;
super.PreloadAssets(Inv, bSkipRefCount);
W = ScrnChainsaw(Inv);
default.EngineStartSound = sound(DynamicLoadObject(default.EngineStartSoundRef, class'sound'));
default.EngineStopSound = sound(DynamicLoadObject(default.EngineStopSoundRef, class'sound'));
for ( i = 0; i < default.ReloadSounds.Length; ++i ) {
default.ReloadSounds[i].Sound = sound(DynamicLoadObject(default.ReloadSounds[i].SoundRef, class'sound'));
if ( W != none ) {
W.ReloadSounds[i].Sound = default.ReloadSounds[i].Sound;
}
}
if ( W != none ) {
W.EngineStartSound = default.EngineStartSound;
W.EngineStopSound = default.EngineStopSound;
W.CalcReloadSoundDuration();
default.TotalReloadSoundDuration = W.TotalReloadSoundDuration;
}
}
static function bool UnloadAssets()
{
local int i;
default.EngineStartSound = none;
default.EngineStopSound = none;
default.TotalReloadSoundDuration = 0;
for ( i = 0; i < default.ReloadSounds.Length; ++i ) {
default.ReloadSounds[i].Sound = none;
}
return super.UnloadAssets();
}
simulated function PostBeginPlay()
{
super.PostBeginPlay();
AttachGasCan();
CalcReloadSoundDuration();
}
simulated function AttachGasCan() {
if ( Level.NetMode != NM_DedicatedServer )
{
if ( FakedGasCan == none ) //only spawn FakedGasCan once
FakedGasCan = spawn(class'ScrnFakedGasCan',self);
if ( FakedGasCan != none )
{
AttachToBone(FakedGasCan, 'Chainsaw'); //attach faked shell to chainsaw
FakedGasCan.SetDrawScale(0.01);
FakedGasCan.SetRelativeLocation(vect(-3, 2, 3)); //x y z
FakedGasCan.SetRelativeRotation(rot(-4000, 38000, 12000)); //pitch yaw roll
}
}
}
simulated function CalcReloadSoundDuration()
{
local int i;
TotalReloadSoundDuration = 0;
for ( i = 0; i < default.ReloadSounds.Length; ++i ) {
ReloadSounds[i].Duration = GetSoundDuration(ReloadSounds[i].Sound);
TotalReloadSoundDuration += ReloadSounds[i].Duration;
}
}
simulated function bool ConsumeAmmo( int Mode, float Load, optional bool bAmountNeededIsMax )
{
local Inventory Inv;
local bool bOutOfAmmo;
local KFWeapon KFWeap;
if ( Super(Weapon).ConsumeAmmo(Mode, Load, bAmountNeededIsMax) )
{
if ( Load > 0 && (Mode == 0 || bReduceMagAmmoOnSecondaryFire) ) {
MagAmmoRemaining -= Load; // Changed from "MagAmmoRemaining--" -- PooSH
if ( MagAmmoRemaining < 0 )
MagAmmoRemaining = 0;
if ( MagAmmoRemaining == 0 ) {
ThirdPersonActor.AmbientSound = none;
TexPanner(Skins[1]).PanRate = 0; // stop saw cycling
PlaySound(EngineStopSound);
}
}
OldMagAmmoRemaining = MagAmmoRemaining;
NetUpdateTime = Level.TimeSeconds - 1;
if ( FireMode[Mode].AmmoPerFire > 0 && InventoryGroup > 0 && !bMeleeWeapon && bConsumesPhysicalAmmo &&
(Ammo[0] == none || FireMode[0] == none || FireMode[0].AmmoPerFire <= 0 || Ammo[0].AmmoAmount < FireMode[0].AmmoPerFire) &&
(Ammo[1] == none || FireMode[1] == none || FireMode[1].AmmoPerFire <= 0 || Ammo[1].AmmoAmount < FireMode[1].AmmoPerFire) )
{
bOutOfAmmo = true;
for ( Inv = Instigator.Inventory; Inv != none; Inv = Inv.Inventory )
{
KFWeap = KFWeapon(Inv);
if ( Inv.InventoryGroup > 0 && KFWeap != none && !KFWeap.bMeleeWeapon && KFWeap.bConsumesPhysicalAmmo &&
((KFWeap.Ammo[0] != none && KFWeap.FireMode[0] != none && KFWeap.FireMode[0].AmmoPerFire > 0 &&KFWeap.Ammo[0].AmmoAmount >= KFWeap.FireMode[0].AmmoPerFire) ||
(KFWeap.Ammo[1] != none && KFWeap.FireMode[1] != none && KFWeap.FireMode[1].AmmoPerFire > 0 && KFWeap.Ammo[1].AmmoAmount >= KFWeap.FireMode[1].AmmoPerFire)) )
{
bOutOfAmmo = false;
break;
}
}
if ( bOutOfAmmo )
{
PlayerController(Instigator.Controller).Speech('AUTO', 3, "");
}
}
return true;
}
return false;
}
simulated function ClientReload()
{
super.ClientReload();
if (FakedGasCan != none)
FakedGasCan.SetDrawScale(2); //test
// if MagAmmoRemaining == 0, chaisaw is already stopped
if ( MagAmmoRemaining > 0 )
PlaySound(EngineStopSound);
ThirdPersonActor.AmbientSound = none;
GotoState('Reloading');
}
simulated function ActuallyFinishReloading()
{
super.ActuallyFinishReloading();
IdleFuelConsumeTime = default.IdleFuelConsumeTime;
GotoState('');
if ( MagAmmoRemaining > 0) {
PlaySound(EngineStartSound);
ThirdPersonActor.AmbientSound = ThirdPersonActor.default.AmbientSound;
TexPanner(Skins[1]).PanRate = 3; // start saw cycling
PlayIdle();
}
}
simulated function ClientFinishReloading()
{
super.ClientFinishReloading();
if ( Level.NetMode != NM_DedicatedServer )
{
if (FakedGasCan != none)
FakedGasCan.SetDrawScale(0.01); //hide gas can after reload
}
}
simulated function WeaponTick(float dt)
{
super.WeaponTick(dt);
if ( Role == Role_Authority ) {
if ( !bIsReloading ) {
if ( MagAmmoRemaining <= 0) {
ThirdPersonActor.AmbientSound = none;
TexPanner(Skins[1]).PanRate = 0; // stop saw cycling
}
else {
if ( Level.TimeSeconds - FireMode[0].NextFireTime > 1.0 && Level.TimeSeconds - FireMode[1].NextFireTime > 1.0 ) {
//consume ammo on idle
IdleFuelConsumeTime -= dt;
if ( IdleFuelConsumeTime <= 0 ) {
ConsumeAmmo(0, 1);
IdleFuelConsumeTime = default.IdleFuelConsumeTime;
}
}
}
}
}
}
// there is no reload animation for Chainsaw, so play slow put down animation
// taking sounds from flamethrower reload
simulated state Reloading
{
simulated function BeginState()
{
NextReloadSoundIndex = 0;
TimeToNextReloadSound = ReloadRate * 0.2;
bBlownUpThisReload = false;
}
simulated function WeaponTick(float dt)
{
super.WeaponTick(dt);
if ( NextReloadSoundIndex < ReloadSounds.length ) {
// if ( NextReloadSoundIndex < ReloadSounds.length - 2 )
// ThirdPersonActor.AmbientSound = none;
TimeToNextReloadSound -= dt;
if ( TimeToNextReloadSound <= 0 ) {
PlaySound(ReloadSounds[NextReloadSoundIndex].Sound);
TimeToNextReloadSound += 0.8*ReloadRate * ReloadSounds[NextReloadSoundIndex].Duration/TotalReloadSoundDuration;
NextReloadSoundIndex++;
}
}
}
function TakeDamage(int Damage, Pawn EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional int HitIndex)
{
local ScrnFlameNade nade;
local int FuelInTank;
//blow the fuel inside a tank on fire damage received (excluding DoT)
if ( bBlownUpThisReload || DamageType == none || Damage < 5 || DamageType == class'DamTypeFlamethrower' )
return;
if ( Level.TimeSeconds > ReloadTimer + ReloadRate*0.9 ) //almost finished reloading, don't blow up
return;
if ( DamageType.default.bFlaming || (class<KFWeaponDamageType>(DamageType) != none && class<KFWeaponDamageType>(DamageType).default.bDealBurningDamage) ) {
bBlownUpThisReload = true;
FuelInTank = MagAmmoRemaining + (MagCapacity - MagAmmoRemaining) * (Level.TimeSeconds - ReloadTimer) / ReloadRate;
if ( FuelInTank > AmmoAmount(0) )
FuelInTank = AmmoAmount(0);
if ( FuelInTank < 1 )
return;
nade = spawn(class'ScrnBalanceSrv.ScrnFlameNade');
HideGasCan();
AttachToBone(nade, 'Chainsaw'); //attempt to move explosion onto chainsaw to make it obvious that the gas can caused the explosion
nade.SetRelativeLocation(vect(-3, 2, 3)); //move nade to exact gas can location
nade.SetTimer(0, false); // it will be blown up manualy
nade.Instigator = Instigator;
// the more fuel in tank, the higher is explosion
nade.Damage = FuelInTank;
AddAmmo(-FuelInTank, 0);
nade.Explode(Location, vect(0,0,1));
}
}
}
simulated function HideGasCan()
{
if ( Level.NetMode != NM_DedicatedServer )
{
FakedGasCan.SetDrawScale(0.01); //hide gas can after reload
}
}
//destroy gas can on destroy
simulated function Destroyed()
{
if ( FakedGasCan != none && !FakedGasCan.bDeleteMe )
FakedGasCan.Destroy();
super.Destroyed();
}
simulated function PlayIdle()
{
if ( MagAmmoRemaining > 0 )
super.PlayIdle();
}
defaultproperties
{
IdleFuelConsumeTime=5.000000
EngineStartSoundRef="KF_ChainsawSnd.Chainsaw_FalseStart4"
EngineStopSoundRef="KF_ChainsawSnd.Chainsaw_Deselect1"
ReloadSounds(0)=(SoundRef="KF_FlamethrowerSnd.FT_Reload1")
ReloadSounds(1)=(SoundRef="KF_FlamethrowerSnd.FT_Reload2")
ReloadSounds(2)=(SoundRef="KF_FlamethrowerSnd.FT_Reload3")
ReloadSounds(3)=(SoundRef="KF_FlamethrowerSnd.FT_Reload4")
ReloadSounds(4)=(SoundRef="KF_FlamethrowerSnd.FT_Reload5")
ReloadSounds(5)=(SoundRef="KF_FlamethrowerSnd.FT_Reload5b")
ReloadSounds(6)=(SoundRef="KF_FlamethrowerSnd.FT_Reload6")
ReloadSounds(7)=(SoundRef="KF_ChainsawSnd.Chainsaw_FalseStart1")
ReloadSounds(8)=(SoundRef="KF_ChainsawSnd.Chainsaw_FalseStart2")
MagCapacity=105
ReloadRate=2.666667
ReloadAnim="PutDown"
ReloadAnimRate=0.250000
WeaponReloadAnim="Reload_Flamethrower"
bAmmoHUDAsBar=True
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnChainsawFire'
FireModeClass(1)=Class'ScrnBalanceSrv.ScrnChainsawAltFire'
bMeleeWeapon=False
bShowChargingBar=True
Description="This legendary chainsaw is used through the centuries to fight evil forces"
PickupClass=Class'ScrnBalanceSrv.ScrnChainsawPickup'
ItemName="Ash's Chainsaw"
}

View file

@ -0,0 +1,49 @@
class ScrnChainsawAltFire extends ChainsawAltFire;
var() int MaxChargeAmmo;
var float LastClickTime;
simulated function bool AllowFire()
{
if(KFWeapon(Weapon).bIsReloading)
return false;
if(KFPawn(Instigator).SecondaryItem!=none)
return false;
if(KFPawn(Instigator).bThrowingNade)
return false;
if(KFWeapon(Weapon).MagAmmoRemaining < MaxChargeAmmo)
{
if( Level.TimeSeconds - LastClickTime>FireRate )
{
LastClickTime = Level.TimeSeconds;
}
if( AIController(Instigator.Controller)!=None )
KFWeapon(Weapon).ReloadMeNow();
return false;
}
return Super.AllowFire();
}
function ModeDoFire()
{
if (!AllowFire())
return;
super.ModeDoFire();
Weapon.ConsumeAmmo(ThisModeNum, MaxChargeAmmo);
}
defaultproperties
{
MaxChargeAmmo=10
MeleeDamage=330
weaponRange=100.000000
hitDamageClass=Class'ScrnBalanceSrv.ScrnDamTypeChainsawAlt'
bWaitForRelease=True
AmmoClass=Class'ScrnBalanceSrv.ScrnChainsawAmmo'
}

View file

@ -0,0 +1,12 @@
class ScrnChainsawAmmo extends ChainsawAmmo;
defaultproperties
{
bAcceptsAmmoPickups=True
AmmoPickupAmount=105
MaxAmmo=1050
InitialAmount=525
PickupClass=Class'ScrnBalanceSrv.ScrnChainsawAmmoPickup'
IconCoords=(X1=336,Y1=82,X2=382,Y2=125)
ItemName="Fuel Canisters"
}

View file

@ -0,0 +1,9 @@
class ScrnChainsawAmmoPickup extends ChainsawAmmoPickup;
defaultproperties
{
AmmoAmount=105
InventoryType=Class'ScrnBalanceSrv.ScrnChainsawAmmo'
PickupMessage="ML of Gasoline"
StaticMesh=StaticMesh'KillingFloorStatics.FT_AmmoMesh'
}

View file

@ -0,0 +1,53 @@
class ScrnChainsawFire extends ChainsawFire;
var float LastClickTime;
simulated function bool AllowFire()
{
if(KFWeapon(Weapon).bIsReloading)
return false;
if(KFPawn(Instigator).SecondaryItem!=none)
return false;
if(KFPawn(Instigator).bThrowingNade)
return false;
if(KFWeapon(Weapon).MagAmmoRemaining < 1)
{
if( Level.TimeSeconds - LastClickTime>FireRate )
{
LastClickTime = Level.TimeSeconds;
}
if( AIController(Instigator.Controller)!=None )
KFWeapon(Weapon).ReloadMeNow();
return false;
}
return Super.AllowFire();
}
function PlayDefaultAmbientSound()
{
local WeaponAttachment WA;
WA = WeaponAttachment(Weapon.ThirdPersonActor);
if ( KFWeapon(Weapon) == none || (WA == none))
return;
WA.SoundVolume = WA.default.SoundVolume;
WA.SoundRadius = WA.default.SoundRadius;
if ( KFWeapon(Weapon).MagAmmoRemaining > 0 )
WA.AmbientSound = WA.default.AmbientSound;
else
WA.AmbientSound = none;
}
defaultproperties
{
MeleeDamage=22
weaponRange=80.000000
hitDamageClass=Class'ScrnBalanceSrv.ScrnDamTypeChainsawAlt'
AmmoClass=Class'ScrnBalanceSrv.ScrnChainsawAmmo'
AmmoPerFire=1
}

View file

@ -0,0 +1,13 @@
class ScrnChainsawPickup extends ChainsawPickup;
defaultproperties
{
cost=1000
BuyClipSize=100
Description="This legendary chainsaw is used through the centuries to fight evil forces"
ItemName="Ash's Chainsaw"
ItemShortName="Ash's Chainsaw"
AmmoItemName="Gasoline"
InventoryType=Class'ScrnBalanceSrv.ScrnChainsaw'
PickupMessage="You got the Ash's Chainsaw."
}

View file

@ -0,0 +1,13 @@
class ScrnClaymoreSword extends ClaymoreSword;
defaultproperties
{
bIsTier2Weapon=False
bIsTier3Weapon=True
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnClaymoreSwordFire'
FireModeClass(1)=Class'ScrnBalanceSrv.ScrnClaymoreSwordFireB'
Priority=105
GroupOffset=4
PickupClass=Class'ScrnBalanceSrv.ScrnClaymoreSwordPickup'
ItemName="Claymore Sword SE"
}

View file

@ -0,0 +1,11 @@
class ScrnClaymoreSwordFire extends ClaymoreSwordFire;
defaultproperties
{
DamagedelayMin=0.570000
DamagedelayMax=0.570000
WideDamageMinHitAngle=0.833333
bWaitForRelease=True
FireAnimRate=1.105263
FireRate=0.950000
}

View file

@ -0,0 +1,5 @@
class ScrnClaymoreSwordFireB extends ClaymoreSwordFireB;
defaultproperties
{
}

View file

@ -0,0 +1,11 @@
class ScrnClaymoreSwordPickup extends ClaymoreSwordPickup;
defaultproperties
{
cost=2500
SpeedValue=45
Description="ScrN version of a medieval claymore sword. Swings faster, can chain ZED times."
ItemName="Claymore Sword SE"
ItemShortName="Claymore SE"
InventoryType=Class'ScrnBalanceSrv.ScrnClaymoreSword'
}

View file

@ -0,0 +1,870 @@
class ScrnClientPerkRepLink extends ClientPerkRepLink
config(ScrnBalance)
dependson(ScrnBalance)
dependson(ScrnAchievements);
var ScrnPlayerController OwnerPC;
var String CurrentJob; // for debug purposes
var byte TotalCategories;
var int TotalWeapons, TotalChars, TotalLocks;
// how many more records client is expecting to receive from the server
// used on client-side only
var transient int PendingItems;
var transient byte PendingCategories;
var transient int PendingWeapons, PendingChars, PendingLocks;
var transient float RepStartTime;
var bool bClientDebug;
var protected int CheckDataAttempts;
const DLC_LOCK_STEAM_APP = 1;
const DLC_LOCK_STEAM_ACH = 2;
const DLC_LOCK_SCRN = 5;
struct SPickupLock {
var class<Pickup> PickupClass;
var byte Group;
var ScrnBalance.ECustomLockType Type;
var name ID;
var material Icon;
var string Title, Text;
var int MaxProgress, CurProgress;
var ScrnAchievements.AchStrInfo AchInfo; // used by LOCK_Ach only
// if true, then lock state can't be changed during the rest of the game anymore,
// and there is no need to parse it anymore
var bool bNoParse;
var bool bUnlocked; // true if this or any in its group unlocked
};
var transient array<SPickupLock> Locks;
var material IconPerkLocked, IconAchLocked, IconGrpLocked, IconChecked;
var protected array<ScrnBalance.SNameValuePair> PermGroupStats; // achievement group stats that do not change during the game
var transient protected array<ScrnBalance.SNameValuePair> GroupStatCache; // cache group stats to avoid multiple calls on the same group
var localized string strLevelTitle, strLevelText;
var localized string strUnknownAchTitle, strUnknownAchText;
var localized string strGrpTitle, strGrpText;
var config float CategorySendCooldown, WeaponSendCooldown, CharacterSendCooldown, SmileSendCooldown;
var config bool bWaitForACK;
replication
{
reliable if ( bNetOwner && bNetInitial && Role == ROLE_Authority )
TotalWeapons, TotalChars, TotalCategories, TotalLocks;
reliable if ( Role < ROLE_Authority )
ServerStartInitialReplication, ServerSelectPerkSE;
reliable if ( Role == ROLE_Authority )
ClientReceiveLevelLock, ClientReceiveAchLock, ClientReceiveGroupLock;
}
// Just look for the stats. Don't do mysterious things as Marco intended in FindStats()
static final function ScrnClientPerkRepLink FindMe( PlayerController MyOwner )
{
local LinkedReplicationInfo L;
local ScrnClientPerkRepLink PerkLink;
if( MyOwner == none || MyOwner.PlayerReplicationInfo == None )
return none;
if ( MyOwner.Level.NetMode != NM_Client && SRStatsBase(MyOwner.SteamStatsAndAchievements) != none ) {
PerkLink = ScrnClientPerkRepLink(SRStatsBase(MyOwner.SteamStatsAndAchievements).Rep);
if ( PerkLink != none )
return PerkLink;
}
for( L=MyOwner.PlayerReplicationInfo.CustomReplicationInfo; L!=None; L=L.NextReplicationInfo ) {
PerkLink = ScrnClientPerkRepLink(L);
if( PerkLink != None )
return PerkLink;
}
if ( MyOwner.Level.NetMode == NM_Client ) {
foreach MyOwner.DynamicActors(Class'ScrnClientPerkRepLink',PerkLink) {
// not added to PRI yet
PerkLink.OwnerPC = ScrnPlayerController(MyOwner);
PerkLink.OwnerPRI = KFPlayerReplicationInfo(MyOwner.PlayerReplicationInfo);
PerkLink.AddMeToPRI();
return PerkLink;
}
}
return none;
}
simulated function AddMeToPRI()
{
local LinkedReplicationInfo L;
if ( OwnerPRI.CustomReplicationInfo == none )
OwnerPRI.CustomReplicationInfo = self;
else {
for( L=OwnerPRI.CustomReplicationInfo; L!=None; L=L.NextReplicationInfo ) {
if( L==self )
return; // Make sure not already added.
if ( L.NextReplicationInfo == none ) {
L.NextReplicationInfo = self;
NextReplicationInfo = none; // avoid circular links in case we received it from server
return;
}
}
}
}
simulated function PostNetBeginPlay()
{
super.PostNetBeginPlay();
if ( Role < ROLE_Authority ) {
log("ScrnClientPerkRepLink spawned", 'ScrnBalance');
StartClientInitialReplication();
}
}
function SendClientPerksSE()
{
local int i;
local class<ScrnVeterancyTypes> Perk;
local byte lvl;
for( i=0; i<CachePerks.Length; i++ ) {
Perk = class<ScrnVeterancyTypes>(CachePerks[i].PerkClass);
if ( Perk.default.bLocked )
lvl = 255;
else
lvl = 0x80 | CachePerks[i].CurrentLevel;
ClientReceivePerk(i, Perk, lvl);
}
}
simulated function ClientReceivePerk( int Index, class<SRVeterancyTypes> V, byte lvl )
{
// Setup correct icon for trader.
if( V.Default.PerkIndex<255 && V.Default.OnHUDIcon!=None )
{
if( ShopPerkIcons.Length <= V.Default.PerkIndex )
ShopPerkIcons.Length = V.Default.PerkIndex+1;
ShopPerkIcons[V.Default.PerkIndex] = V.Default.OnHUDIcon;
}
if( CachePerks.Length <= Index )
CachePerks.Length = Index+1;
CachePerks[Index].PerkClass = V;
ClientPerkLevel(Index, lvl);
}
simulated function ClientPerkLevel( int Index, byte NewLevel )
{
if ( NewLevel == 255 ) {
class<ScrnVeterancyTypes>(CachePerks[Index].PerkClass).default.bLocked = true;
CachePerks[Index].CurrentLevel = 0;
}
else if ( (NewLevel & 0x80) > 0 ) {
// highest bit indicates that perk should be unlocked
class<ScrnVeterancyTypes>(CachePerks[Index].PerkClass).default.bLocked = false;
CachePerks[Index].CurrentLevel = NewLevel & 0x7F;
}
else if ( class<ScrnVeterancyTypes>(CachePerks[Index].PerkClass).default.bLocked == false ) {
if ( CachePerks[Index].CurrentLevel > 0 && NewLevel > CachePerks[Index].CurrentLevel )
Level.GetLocalPlayerController().ReceiveLocalizedMessage(Class'ScrnPromotedMessage',(NewLevel-1),,,CachePerks[Index].PerkClass);
CachePerks[Index].CurrentLevel = NewLevel;
}
}
function ServerSelectPerkSE(Class<ScrnVeterancyTypes> VetType)
{
local KFGameType KF;
local bool bDifferentPerk;
KF = KFGameType(Level.Game);
if ( VetType == none || VetType.default.bLocked )
OwnerPC.ClientMessage(OwnerPC.strPerkLocked);
else if ( OwnerPC == none || KF == none || KF.bWaitingToStartMatch || OwnerPC.Mut.bAllowAlwaysPerkChanges )
StatObject.ServerSelectPerk(VetType); // shouldn't happen, but just to be sure...
else {
if ( OwnerPC.Mut.bNoPerkChanges && OwnerPC.bHadPawn
&& (!OwnerPC.Mut.bPerkChangeBoss || OwnerPC.Mut.bTSCGame || KF.WaveNum < KF.FinalWave)
&& (!OwnerPC.Mut.bPerkChangeDead || (OwnerPC.Pawn != none && OwnerPC.Pawn.Health > 0)) )
{
OwnerPC.ClientMessage(OwnerPC.strNoPerkChanges);
return;
}
if ( KF.WaveNum == OwnerPC.PerkChangeWave && !KF.bWaveInProgress ) {
OwnerPC.ClientMessage(OwnerPC.PerkChangeOncePerWaveString);
return;
}
bDifferentPerk = OwnerPRI != none && VetType != OwnerPRI.ClientVeteranSkill;
StatObject.ServerSelectPerk(VetType);
if ( bDifferentPerk && VetType == OwnerPRI.ClientVeteranSkill )
OwnerPC.PerkChangeWave = KF.WaveNum;
}
}
// this is triggered every time client receives any item from the server
simulated function OnClientRepItemReceived() {}
simulated function ClientReceiveCategory( byte Index, FShopCategoryIndex S )
{
if ( bClientDebug )
OwnerPC.ClientMessage("Category " $ (Index+1)$"/"$TotalCategories@ S.Name);
--PendingCategories;
--PendingItems;
++ClientAccknowledged[1];
ShopCategories[Index] = S;
OnClientRepItemReceived();
}
simulated function ClientReceiveWeapon( int Index, class<Pickup> P, byte Categ )
{
if ( bClientDebug )
OwnerPC.ClientMessage("Weapon " $ (Index+1)$"/"$TotalWeapons @ P);
--PendingWeapons;
--PendingItems;
++ClientAccknowledged[0];
ShopInventory[Index].PC = P;
ShopInventory[Index].CatNum = Categ;
OnClientRepItemReceived();
}
simulated function ClientReceiveLevelLock(int Index, class<Pickup> PC, byte Group, byte MinLevel)
{
if ( bClientDebug )
OwnerPC.ClientMessage("LevelLock " $ (Index+1)$"/"$TotalLocks @ PC);
--PendingLocks;
--PendingItems;
Locks[Index].Type = LOCK_Level;
Locks[Index].PickupClass = PC;
Locks[Index].Group = Group;
Locks[Index].MaxProgress = MinLevel;
OnClientRepItemReceived();
}
simulated function ClientReceiveAchLock(int Index, class<Pickup> PC, byte Group, name Achievement)
{
if ( bClientDebug )
OwnerPC.ClientMessage("AchLock " $ (Index+1)$"/"$TotalLocks @ PC @ Achievement);
--PendingLocks;
--PendingItems;
Locks[Index].Type = LOCK_Ach;
Locks[Index].PickupClass = PC;
Locks[Index].Group = Group;
Locks[Index].ID = Achievement;
OnClientRepItemReceived();
}
simulated function ClientReceiveGroupLock(int Index, class<Pickup> PC, byte Group, name AchGroup, byte Count)
{
if ( bClientDebug )
OwnerPC.ClientMessage("GroupLock " $ (Index+1)$"/"$TotalLocks @ PC@ AchGroup);
--PendingLocks;
--PendingItems;
Locks[Index].Type = LOCK_AchGroup;
Locks[Index].PickupClass = PC;
Locks[Index].Group = Group;
Locks[Index].ID = AchGroup;
Locks[Index].MaxProgress = Count;
OnClientRepItemReceived();
}
simulated function ClientReceiveChar( string CharName, int Num )
{
if ( bClientDebug )
OwnerPC.ClientMessage("Character " $ (Num+1)$"/"$TotalChars@ CharName);
--PendingChars;
--PendingItems;
++ClientAckSkinNum;
CustomChars[Num] = CharName;
OnClientRepItemReceived();
}
simulated function ClientReceiveTag( Texture T, string Tag, bool bInCaps )
{
super.ClientReceiveTag(T, Tag, bInCaps);
if( OwnerPC!=None && SRHUDKillingFloor(OwnerPC.MyHUD)!=None )
SRHUDKillingFloor(OwnerPC.MyHUD).SmileyMsgs = SmileyTags;
}
simulated function ClientSendAcknowledge()
{
ServerAcnowledge(ClientAccknowledged[0],ClientAccknowledged[1]);
ServerAckSkin(ClientAckSkinNum);
}
simulated function ClientAllReceived()
{
local PlayerController LocalPC;
local int i;
local class<KFWeapon> WC;
bRepCompleted = true;
//PendingItems = 0;
LocalPC = Level.GetLocalPlayerController();
// Owner is unreliable on client side
if( (LocalPC!=None && LocalPC==Owner) || Level.NetMode==NM_Client ) {
InitCustomLocks();
// Marks Steam DLC requirements
for( i=0; i<ShopInventory.length; ++i ) {
if ( ShopInventory[i].bDLCLocked != DLC_LOCK_SCRN ) {
WC = class<KFWeapon>(ShopInventory[i].PC.Default.InventoryType);
if ( WC != none && WC.Default.AppID > 0 )
ShopInventory[i].bDLCLocked = DLC_LOCK_STEAM_APP;
}
}
Spawn(Class'ScrnSteamStatsGetter',LocalPC).Link = self;
}
if( SmileyTags.Length > 0 && LocalPC!=None && SRHUDKillingFloor(LocalPC.MyHUD)!=None )
SRHUDKillingFloor(LocalPC.MyHUD).SmileyMsgs = SmileyTags;
}
simulated protected function int GetAchGroupProgress(name GroupName)
{
local int i, v, m;
for ( i=0; i<PermGroupStats.length; ++i ) {
if ( PermGroupStats[i].ID == GroupName )
return PermGroupStats[i].Value;
}
for ( i=0; i<GroupStatCache.length; ++i ) {
if ( GroupStatCache[i].ID == GroupName )
return GroupStatCache[i].Value;
}
class'ScrnAchievements'.static.GetGlobalAchievementStats(self, v, m, 0, GroupName);
GroupStatCache.insert(i, 1);
GroupStatCache[i].ID = GroupName;
GroupStatCache[i].Value = v;
return v;
}
// fills permanent data of Locks. Should be called only once. But it is safe to call it multiple times
simulated function InitCustomLocks()
{
local int i, j, a;
local string s, g;
local class<Pickup> PC;
// load and store map achievement stats
for ( i=0; i<PermGroupStats.length; ++i ) {
class'ScrnAchievements'.static.GetGlobalAchievementStats(self, j, a, 0, PermGroupStats[i].ID);
PermGroupStats[i].Value = j;
}
for ( i=0; i<Locks.length; ++i ) {
// mark corresponding shop inventory items as ScrN-locked
if ( Locks[i].PickupClass != PC ) {
PC = Locks[i].PickupClass;
for( j=0; j<ShopInventory.Length; ++j ) {
if ( ShopInventory[j].PC == PC )
ShopInventory[j].bDLCLocked = DLC_LOCK_SCRN;
}
}
switch ( Locks[i].Type ) {
case LOCK_Level:
if ( Level.NetMode != NM_DedicatedServer ) {
Locks[i].Icon = IconPerkLocked;
s = strLevelTitle;
ReplaceText(s, "%C", string(Locks[i].MaxProgress));
Locks[i].Title = s;
s = strLevelText;
ReplaceText(s, "%C", string(Locks[i].MaxProgress));
Locks[i].Text = s;
}
break;
case LOCK_Ach:
Locks[i].AchInfo = class'ScrnAchievements'.static.GetAchievementByID(self, Locks[i].ID);
if ( Locks[i].AchInfo.AchHandler == none ) {
if ( Level.NetMode != NM_DedicatedServer ) {
Locks[i].Title = strUnknownAchTitle;
Locks[i].Text = strUnknownAchText;
Locks[i].Icon = IconAchLocked;
}
Locks[i].MaxProgress = 1;
Locks[i].CurProgress = 0;
Locks[i].bNoParse = true;
}
else if ( Level.NetMode != NM_DedicatedServer ) {
Locks[i].Title = Locks[i].AchInfo.AchHandler.AchDefs[Locks[i].AchInfo.AchIndex].DisplayName;
Locks[i].Text = Locks[i].AchInfo.AchHandler.AchDefs[Locks[i].AchInfo.AchIndex].Description;
Locks[i].Icon = Locks[i].AchInfo.AchHandler.GetIcon(Locks[i].AchInfo.AchIndex);
}
break;
case LOCK_AchGroup:
// map achievements can't change during the game, so get stats only once
for ( j=0; j<PermGroupStats.length; ++j ) {
if ( PermGroupStats[j].ID == Locks[i].ID ) {
Locks[i].CurProgress = PermGroupStats[j].Value;
Locks[i].bNoParse = true;
}
}
if ( Level.NetMode != NM_DedicatedServer ) {
g = class'ScrnAchievements'.static.GroupCaption(self, Locks[i].ID);
s = strGrpTitle;
ReplaceText(s, "%C", string(Locks[i].MaxProgress));
ReplaceText(s, "%G", g);
Locks[i].Title = s;
s = strGrpText;
ReplaceText(s, "%C", string(Locks[i].MaxProgress));
ReplaceText(s, "%G", g);
Locks[i].Text = s;
if ( Locks[i].CurProgress >= Locks[i].MaxProgress )
Locks[i].Icon = IconChecked;
else
Locks[i].Icon = IconGrpLocked;
}
break;
}
}
ParseLocks();
}
simulated function ParseLocks()
{
local int i, PerkLevel;
GroupStatCache.length = 0; // force update
// just to be sure
// if ( OwnerPRI == none ) {
// if ( Role == ROLE_Authority )
// OwnerPRI = KFPlayerReplicationInfo(StatObject.PlayerOwner.PlayerReplicationInfo);
// else
// OwnerPRI = KFPlayerReplicationInfo(Level.GetLocalPlayerController().PlayerReplicationInfo);
// }
if ( OwnerPRI != none )
PerkLevel = OwnerPRI.ClientVeteranSkillLevel;
for ( i=0; i<Locks.length; ++i ) {
if ( Locks[i].bNoParse )
continue;
switch ( Locks[i].Type ) {
case LOCK_Level:
Locks[i].CurProgress = PerkLevel;
if ( Locks[i].CurProgress >= Locks[i].MaxProgress )
Locks[i].Icon = IconChecked;
else
Locks[i].Icon = IconPerkLocked;
break;
case LOCK_Ach:
Locks[i].MaxProgress = Locks[i].AchInfo.AchHandler.AchDefs[Locks[i].AchInfo.AchIndex].MaxProgress;
Locks[i].CurProgress = Locks[i].AchInfo.AchHandler.AchDefs[Locks[i].AchInfo.AchIndex].CurrentProgress;
if ( Locks[i].CurProgress >= Locks[i].MaxProgress ) {
Locks[i].Icon = Locks[i].AchInfo.AchHandler.GetIcon(Locks[i].AchInfo.AchIndex);
Locks[i].bNoParse = true;
}
break;
case LOCK_AchGroup:
Locks[i].CurProgress = GetAchGroupProgress(Locks[i].ID);
if ( Locks[i].CurProgress >= Locks[i].MaxProgress ) {
Locks[i].Icon = IconChecked;
Locks[i].bNoParse = true;
}
break;
}
}
}
/**
* Function checks if shop inventory item is locked by ScrN locks.
* It assumes that Locks have already been parsed and sorted by group number.
* Call ParseLocks() to ensure that Locks have been parsed.
* @param Index item index in ShopInventory array
* @return true if shop inventory item is unlocked (available for purchase)
*/
simulated function bool IsShopInventoryUnlocked(int Index)
{
local byte result;
if ( Index <= 0 || Index >= ShopInventory.Length )
return false;
if ( ShopInventory[Index].bDLCLocked != DLC_LOCK_SCRN )
return true;
result = IsPickupUnlocked(ShopInventory[Index].PC);
if (result == 2)
ShopInventory[Index].bDLCLocked = 0; // permanently mark item as unlocked
return result > 0;
}
/**
* Function checks if item is locked by ScrN locks.
* It assumes that Locks have already been parsed and sorted by group number.
* @param PC item class to check
* @return 0 - item is locked
* 1 - temporary unlocked (may change during game)
* 2 - permanently unlocked (will stay unlocked till the rest of the game and no need to check it anymore)
*/
simulated function byte IsPickupUnlocked(class<Pickup> PC)
{
local int i, j;
local byte LastLockedGroup, LastUnlockedGroup;
local bool bLevelLock;
for ( i=0; i<Locks.length; ++i ) {
if ( Locks[i].PickupClass != PC || Locks[i].bUnlocked )
continue;
if ( LastLockedGroup > 0 && Locks[i].Group != LastLockedGroup )
return 0; // previous group wan't unlocked
if ( Locks[i].CurProgress >= Locks[i].MaxProgress ) {
// this achievement is unlocked
LastUnlockedGroup = Locks[i].Group;
LastLockedGroup = 0; // make sure this group is not locked anymore
if ( Locks[i].Type == LOCK_Level )
bLevelLock = true; // level lock isn't permanent
else {
Locks[i].bUnlocked = true;
if ( LastUnlockedGroup > 0 ) {
// mark all locks in the current group as unlocked
for ( j=0; j<Locks.length; ++j ) {
if ( Locks[j].PickupClass == PC && Locks[j].Group == LastUnlockedGroup )
Locks[j].bUnlocked = true;
}
}
}
}
else if ( Locks[i].Group == 0 )
return 0;
else if ( Locks[i].Group != LastUnlockedGroup )
LastLockedGroup = Locks[i].Group; // check if next achievements in the same group are unlocked
}
if ( LastLockedGroup > 0 )
return 0;
// if we reached here, than item is unlocked
if ( bLevelLock )
return 1;
return 2;
}
simulated function Tick( float DeltaTime )
{
Disable('Tick');
// if replication link is broken, then it is better for client to reconnect rather
// than trying "fixing" stuff, which at the end makes things even worse
}
//=============================================================================
// CLIENT STATES
//=============================================================================
simulated function StartClientInitialReplication()
{
if ( Role == ROLE_Authority )
return;
GotoState('ClientInitialWaiting');
}
simulated state ClientInitialWaiting
{
ignores StartClientInitialReplication;
Begin:
CurrentJob="Looking for KFPlayerReplicationInfo";
// first make sure OwnerPC and OwnerPRI are replicated
while (true) {
if ( OwnerPC == none )
OwnerPC = ScrnPlayerController(Level.GetLocalPlayerController());
if ( OwnerPC != none )
OwnerPRI = KFPlayerReplicationInfo(OwnerPC.PlayerReplicationInfo);
if ( OwnerPRI != none )
break;
sleep(0.5);
}
// C&P from ServerPerks.ClientPerkRepLink.Tick()
if ( !bRepCompleted )
Class'SRLevelCleanup'.Static.AddSafeCleanup(OwnerPC);
AddMeToPRI();
bClientDebug = OwnerPC.bDebugRepLink;
bRepCompleted = false;
ShopCategories.Length = TotalCategories;
ShopInventory.Length = TotalWeapons;
Locks.Length = TotalLocks;
CustomChars.Length = TotalChars;
PendingCategories = TotalCategories;
PendingWeapons = TotalWeapons;
PendingLocks = TotalLocks;
PendingChars = TotalChars;
PendingItems = TotalCategories + TotalWeapons + TotalLocks + TotalChars;
ClientAccknowledged[0] = 0;
ClientAccknowledged[1] = 0;
ClientAckSkinNum = 0;
sleep(frand()*2.0);
// tell server that we are ready to receive data
ServerStartInitialReplication();
GotoState('ReceivingData');
}
// client state
simulated state ReceivingData
{
ignores StartClientInitialReplication;
simulated function BeginState()
{
if ( Level.NetMode != NM_Client ) {
GotoState(''); // just in case
return;
}
SetTimer(10.0, true); // give server reasonable time to send us data
CurrentJob = "Receiving Data";
RepStartTime = Level.TimeSeconds;
log("["$Level.TimeSeconds$"s] Waiting for server data: Categories="$TotalCategories $ " Weapons="$TotalWeapons
$ " DLCLocks="$TotalLocks $ " Characters="$TotalChars, 'ScrnBalance');
}
simulated function EndState()
{
SetTimer(0, false);
}
simulated function Timer()
{
CheckData();
}
simulated function CheckData()
{
local bool ok;
--CheckDataAttempts;
if ( PendingCategories > 0 )
CurrentJob = "Receiving Categories";
else if ( PendingWeapons > 0 )
CurrentJob = "Receiving Weapons";
else if ( PendingLocks > 0 )
CurrentJob = "Receiving DLC Locks";
else
ok = true;
if ( !ok && CheckDataAttempts > 0 ) {
// wait for receiving all categories, weapons and locks before proceed further
SetTimer(2.0, false);
return;
}
if ( !bRepCompleted ) {
// call it before receiving custom characters
ClientAllReceived();
// tell server that we've got all weapons
ServerAcnowledge(ClientAccknowledged[0],ClientAccknowledged[1]);
}
// characters
if ( ok )
CurrentJob = "Receiving Characters";
if ( PendingChars > 0 && CheckDataAttempts > 0 ) {
// not all custom characters are received yet
SetTimer(2.0, false);
return;
}
ServerAckSkin(CustomChars.Length); // tell server that we've got all characters
if ( PendingItems == 0 ) {
CurrentJob = "ALL OK";
log("["$Level.TimeSeconds$"s] All data received from the server in " $string(Level.TimeSeconds-RepStartTime)$"s", 'ScrnBalance');
}
else {
log("["$Level.TimeSeconds$"s] Unable to receive "$PendingItems$" items", 'ScrnBalance');
}
NetPriority = 1.0;
GotoState('');
}
simulated function OnClientRepItemReceived()
{
if ( PendingItems > 0 )
SetTimer(2.0, true); // take a little pause before checking - more items should come from server
else
CheckData(); // no pending items left, check now
}
}
//=============================================================================
// SERVER STATES
//=============================================================================
function ServerStartInitialReplication()
{
if ( !Level.Game.bGameEnded )
GotoState('InitialReplication');
}
auto state RepSetup
{
Begin:
CurrentJob = "RepSetup";
sleep(1.0);
// OwnerPC and OwnerPRI on server side now are set in ScrnBalance.SetupRepLink
if( NetConnection(StatObject.PlayerOwner.Player)==None ) {
AddMeToPRI(); // ScrnBalance doesn't need that. But it is used by ServerPerks.
// standalone or server listener
bReceivedURL = true;
ClientAllReceived();
CurrentJob = "Solo or Listen Server";
GoToState('UpdatePerkProgress');
}
}
// Sending replication data for the first time.
// No ACK checks here - clients should request missing data later.
state InitialReplication
{
ignores ServerStartInitialReplication;
//ignores ServerRequestCategories, ServerRequestWeapons, ServerRequestChars;
Begin:
AddMeToPRI(); // do it here to prevent redudant replication of NextReplicationInfo
CurrentJob = "InitialReplication";
if( Level.NetMode==NM_Client || NetConnection(StatObject.PlayerOwner.Player)==None )
Stop;
NetUpdateFrequency = 0.5; // this doesn't affect replication of function calls
ClientReceiveURL(ServerWebSite,StatObject.PlayerOwner.GetPlayerIDHash());
sleep(0.2);
CurrentJob = "Sending Perks";
SendClientPerksSE();
NextRepTime = Level.TimeSeconds + 5.0; // no effin spamming us until we're done
sleep(1.0);
CurrentJob = "Sending Categories";
for( SendIndex=0; SendIndex<ShopCategories.Length; ++SendIndex ) {
ClientReceiveCategory(SendIndex, ShopCategories[SendIndex]);
NextRepTime += CategorySendCooldown;
Sleep(CategorySendCooldown);
}
CurrentJob = "Sending Weapons";
for( SendIndex=0; SendIndex<ShopInventory.Length; ++SendIndex ) {
ClientReceiveWeapon(SendIndex, ShopInventory[SendIndex].PC, ShopInventory[SendIndex].CatNum);
NextRepTime += WeaponSendCooldown;
Sleep(WeaponSendCooldown);
}
CurrentJob = "Sending DLC Locks";
for( SendIndex=0; SendIndex<Locks.Length; ++SendIndex ) {
switch (Locks[SendIndex].Type) {
case LOCK_Level:
ClientReceiveLevelLock(SendIndex, Locks[SendIndex].PickupClass, Locks[SendIndex].Group,
Locks[SendIndex].MaxProgress);
break;
case LOCK_Ach:
ClientReceiveAchLock(SendIndex, Locks[SendIndex].PickupClass, Locks[SendIndex].Group,
Locks[SendIndex].ID);
break;
case LOCK_AchGroup:
ClientReceiveGroupLock(SendIndex, Locks[SendIndex].PickupClass, Locks[SendIndex].Group,
Locks[SendIndex].ID, Locks[SendIndex].MaxProgress);
break;
}
NextRepTime += WeaponSendCooldown;
Sleep(WeaponSendCooldown);
}
CurrentJob = "Sending Characters";
for( SendIndex=0; SendIndex<CustomChars.Length; ++SendIndex ) {
ClientReceiveChar(CustomChars[SendIndex],SendIndex);
NextRepTime += CharacterSendCooldown;
Sleep(CharacterSendCooldown);
}
GoToState('WaitingForACK');
}
// server is waiting for client's acknowledgement that everything is received
state WaitingForACK
{
ignores ServerStartInitialReplication;
Begin:
sleep(1.0);
if ( bWaitForACK ) {
CurrentJob = "Waiting for Weapon ACK";
SendIndex = 0;
while ( ClientAccknowledged[0]<ShopInventory.Length || ClientAccknowledged[1]<ShopCategories.Length ) {
if ( ++SendIndex == 10 ) {
ClientSendAcknowledge();
SendIndex = 0;
}
sleep(1.0);
}
CurrentJob = "Waiting for Character ACK";
SendIndex = 0;
while ( ClientAckSkinNum < CustomChars.length ) {
if ( ++SendIndex == 10 ) {
ClientSendAcknowledge();
SendIndex = 0;
}
sleep(1.0);
}
}
bRepCompleted = true;
CurrentJob = "Sending Smiles";
for( SendIndex=0; SendIndex<SmileyTags.Length; ++SendIndex )
{
ClientReceiveTag(SmileyTags[SendIndex].SmileyTex,SmileyTags[SendIndex].SmileyTag,SmileyTags[SendIndex].bInCAPS);
Sleep(SmileSendCooldown);
}
SmileyTags.Length = 0; // we don't need that on server
CurrentJob = "ALL OK";
sleep(5.0);
NetPriority = 1.0;
GotoState('UpdatePerkProgress');
}
defaultproperties
{
CheckDataAttempts=30
IconPerkLocked=Texture'ScrnAch_T.Achievements.PerkLocked'
IconAchLocked=Texture'KillingFloorHUD.Achievements.KF_Achievement_Lock'
IconGrpLocked=Texture'ScrnAch_T.Achievements.AchGroupLocked'
IconChecked=Texture'ScrnAch_T.Achievements.Checked'
PermGroupStats(0)=(id="Map")
PermGroupStats(1)=(id="MAP_Normal")
PermGroupStats(2)=(id="MAP_Hard")
PermGroupStats(3)=(id="MAP_Sui")
PermGroupStats(4)=(id="MAP_HoE")
strLevelTitle="Perk Level %C"
strLevelText="This item has minimal perk level restriction."
strUnknownAchTitle="Unknown Achievement"
strUnknownAchText="Item can't be unlocked in the current game mode"
strGrpTitle="%C %G Achievements"
strGrpText="Unlock %C achievements in '%G' group to unlock this item."
CategorySendCooldown=0.100000
WeaponSendCooldown=0.025000
CharacterSendCooldown=0.100000
SmileSendCooldown=0.100000
NetPriority=1.300000
}

View file

@ -0,0 +1,13 @@
class ScrnCombatVestPickup extends ScrnVestPickup
notplaceable;
defaultproperties
{
ShieldCapacity=100
Weight=1.000000
cost=300
PowerValue=50
ItemName="Combat Armor"
ItemShortName="Combat Armor"
PickupMessage="You got a Combat Armor"
}

View file

@ -0,0 +1,8 @@
class ScrnCrossbow extends Crossbow;
defaultproperties
{
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnCrossbowFire'
PickupClass=Class'ScrnBalanceSrv.ScrnCrossbowPickup'
ItemName="Compound Crossbow SE"
}

View file

@ -0,0 +1,35 @@
class ScrnCrossbowArrow extends CrossbowArrow;
simulated state OnWall
{
function ProcessTouch (Actor Other, vector HitLocation)
{
local Pawn PawnOther;
local Inventory inv;
local Crossbow bow;
PawnOther = Pawn(Other);
if( PawnOther != none ) {
for( inv=PawnOther.Inventory; inv != none; inv = inv.Inventory ) {
bow = Crossbow(inv);
if( bow != none ) {
if ( bow.AmmoAmount(0) < bow.MaxAmmo(0) ) {
bow.AddAmmo(1,0) ;
PlaySound(Sound'KF_InventorySnd.Ammo_GenericPickup', SLOT_Pain,2*TransientSoundVolume,,400);
if( PlayerController(PawnOther.Controller)!=none )
{
PlayerController(PawnOther.Controller).ReceiveLocalizedMessage(class'KFmod.ProjectilePickupMessage',0);
}
Destroy();
}
return;
}
}
}
}
}
defaultproperties
{
LifeSpan=60.000000
}

View file

@ -0,0 +1,7 @@
class ScrnCrossbowFire extends CrossbowFire;
defaultproperties
{
ProjSpawnOffset=(X=0.000000)
ProjectileClass=Class'ScrnBalanceSrv.ScrnCrossbowArrow'
}

View file

@ -0,0 +1,10 @@
class ScrnCrossbowPickup extends CrossbowPickup;
defaultproperties
{
cost=1600
AmmoCost=120
ItemName="Crossbow SE"
ItemShortName="Crossbow SE"
InventoryType=Class'ScrnBalanceSrv.ScrnCrossbow'
}

View file

@ -0,0 +1,9 @@
class ScrnCrossbuzzsaw extends Crossbuzzsaw;
defaultproperties
{
Weight=9.000000
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnCrossbuzzsawFire'
PickupClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawPickup'
ItemName="Buzzsaw Bow SE"
}

View file

@ -0,0 +1,8 @@
class ScrnCrossbuzzsawAmmo extends CrossbuzzsawAmmo;
defaultproperties
{
AmmoPickupAmount=2
MaxAmmo=20
PickupClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawPickup'
}

View file

@ -0,0 +1,6 @@
class ScrnCrossbuzzsawAmmoPickup extends CrossbuzzsawAmmoPickup;
defaultproperties
{
InventoryType=Class'ScrnBalanceSrv.ScrnCrossbuzzsawAmmo'
}

View file

@ -0,0 +1,218 @@
class ScrnCrossbuzzsawBlade extends CrossbuzzsawBlade;
var Actor ImpactActorFixed; // original ImpactActor isn't replicated corectly
var float ShutMeUpTime;
replication
{
reliable if ( Role==ROLE_Authority )
ImpactActorFixed;
}
simulated function PostBeginPlay()
{
super.PostBeginPlay();
ShutMeUpTime += Level.TimeSeconds;
}
simulated function PostNetReceive()
{
if ( Role < ROLE_Authority ){
if ( bHidden )
Destroy();
else if( ImpactActorFixed!=None && Base != ImpactActorFixed )
GoToState('OnWall');
}
}
// destroy an actor and make sure it will be destroyed on clients too
simulated function ReplicatedDestroy()
{
if ( Level.NetMode == NM_Client || Level.NetMode == NM_StandAlone ) {
Destroy();
}
else {
bHidden = true;
SetCollision(false, false);
SetPhysics(PHYS_None);
Velocity = vect(0,0,0);
Speed = 0;
NetUpdateTime = Level.TimeSeconds - 1;
SetTimer(1.0, false);
}
}
function Timer()
{
Destroy();
}
simulated function Tick( float Delta )
{
super.Tick(Delta);
if ( AmbientSound != None && ShutMeUpTime > Level.TimeSeconds )
AmbientSound = None; // make sure I'll shutup
}
// overrided to change calss to ReplicatedDestroy()
simulated state OnWall
{
Ignores HitWall;
simulated function BeginState()
{
bCollideWorld = False;
AmbientSound = None;
if( Trail!=None )
Trail.mRegen = False;
if( Corona != none )
{
Corona.Kill();
}
SetCollisionSize(75,50);
UV2Texture=FadeColor'PatchTex.Common.PickupOverlay';
NetUpdateFrequency = 2.0;
}
function ProcessTouch (Actor Other, vector HitLocation)
{
local Inventory inv;
if( !bHidden && Pawn(Other)!=None && Pawn(Other).Inventory!=None )
{
for( inv=Pawn(Other).Inventory; inv!=None; inv=inv.Inventory )
{
if( Crossbuzzsaw(Inv)!=None && Weapon(inv).AmmoAmount(0)<Weapon(inv).MaxAmmo(0) )
{
KFweapon(Inv).AddAmmo(1,0) ;
PlaySound(Sound'KF_InventorySnd.Ammo_GenericPickup', SLOT_Pain,2*TransientSoundVolume,,400);
if( PlayerController(Instigator.Controller)!=none )
{
PlayerController(Instigator.Controller).ReceiveLocalizedMessage(class'KFmod.ProjectilePickupMessage',1);
}
ReplicatedDestroy();
}
}
}
}
simulated function Tick( float Delta )
{
if( Base==None )
ReplicatedDestroy();
}
}
simulated function ProcessTouch (Actor Other, vector HitLocation)
{
local vector X;
local Vector TempHitLocation, HitNormal;
local array<int> HitPoints;
local KFPawn HitPawn;
local bool bHitWhipAttachment;
local Pawn P;
if ( bHidden || Other == none || Other == Instigator || Other.Base == Instigator || !Other.bBlockHitPointTraces || Other==IgnoreImpactPawn ||
(IgnoreImpactPawn != none && Other.Base == IgnoreImpactPawn) )
return;
X = Vector(Rotation);
if( ROBulletWhipAttachment(Other) != none )
{
bHitWhipAttachment=true;
if(!Other.Base.bDeleteMe)
{
Other = Instigator.HitPointTrace(TempHitLocation, HitNormal, HitLocation + (65535 * X), HitPoints, HitLocation,, 1);
if( Other == none || HitPoints.Length == 0 )
return;
HitPawn = KFPawn(Other);
if (Role == ROLE_Authority)
{
if ( HitPawn != none )
{
// Hit detection debugging
/*log("Bullet hit "$HitPawn.PlayerReplicationInfo.PlayerName);
HitPawn.HitStart = HitLocation;
HitPawn.HitEnd = HitLocation + (65535 * X);*/
if( !HitPawn.bDeleteMe )
HitPawn.ProcessLocationalDamage(Damage, Instigator, TempHitLocation, MomentumTransfer * X, MyDamageType,HitPoints);
Damage *= 0.80;
Velocity *= 0.85;
IgnoreImpactPawn = HitPawn;
if( Level.NetMode!=NM_Client )
PlayhitNoise(Pawn(Other)!=none && Pawn(Other).ShieldStrength>0);
}
}
}
return;
}
if ( Pawn(Other)!=None && Vehicle(Other)==None )
P = Pawn(Other);
else if ( ExtendedZCollision(Other)!=None && Pawn(Other.Owner)!=None )
P = Pawn(Other.Owner);
if( Level.NetMode!=NM_Client )
PlayhitNoise(P != none && P.ShieldStrength>0 );
if( P != none ) {
IgnoreImpactPawn = P;
if( P.IsHeadShot(HitLocation, X, 1.0) )
P.TakeDamage(Damage * HeadShotDamageMult, Instigator, HitLocation, MomentumTransfer * X, DamageTypeHeadShot);
else
P.TakeDamage(Damage, Instigator, HitLocation, MomentumTransfer * X, MyDamageType);
// If blade kills pawn, decatipates it or it was already decapitated,
// then apply lower damage and speed reduction
// -- PooSH
if ( Physics==PHYS_Projectile && (P == none || P.Health <= 0 || (KFMonster(P) != none && KFMonster(P).bDecapitated)) ) {
Damage *= 0.85; // vanilla = 0.8
Velocity *= 0.9; // vanilla = 0.85
}
else {
Damage *= 0.60; // vanilla = 0.8
Velocity *= 0.75; // vanilla = 0.85
if ( Damage < default.Damage * 0.50 ) {
if ( Bounces > 0 )
Bounces--; // lower amount of bounces, if blade hit many zeds already
if ( Role == ROLE_Authority && Bounces == 0 && Damage < default.Damage * 0.20 )
ReplicatedDestroy();
}
}
}
else {
Other.TakeDamage(Damage, Instigator, HitLocation, MomentumTransfer * X, MyDamageType);
}
}
simulated function Stick(actor HitActor, vector HitLocation)
{
super.Stick(HitActor, HitLocation);
ImpactActorFixed = ImpactActor; // replicate properly
NetUpdateTime = Level.TimeSeconds - 1;
}
defaultproperties
{
ShutMeUpTime=10.000000
HeadShotDamageMult=2.500000
Damage=400.000000
DamageRadius=0.000000
MyDamageType=Class'ScrnBalanceSrv.ScrnDamTypeCrossbuzzsaw'
LifeSpan=60.000000
}

View file

@ -0,0 +1,7 @@
class ScrnCrossbuzzsawFire extends CrossbuzzsawFire;
defaultproperties
{
AmmoClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawAmmo'
ProjectileClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawBlade'
}

View file

@ -0,0 +1,9 @@
class ScrnCrossbuzzsawPickup extends CrossbuzzsawPickup;
defaultproperties
{
Weight=9.000000
ItemName="Buzzsaw Bow SE"
ItemShortName="Buzzsaw Bow SE"
InventoryType=Class'ScrnBalanceSrv.ScrnCrossbuzzsaw'
}

View file

@ -0,0 +1,215 @@
class ScrnCustomPRI extends LinkedReplicationInfo;
var byte BlameCounter;
var private Material Avatar, ClanIcon, PreNameIcon, PostNameIcon;
var Color PrefixIconColor, PostfixIconColor;
var private int TourneyPlayoffs, TourneyWins;
var private string SteamID64;
var private int SteamID32, ClientSteamID32;
var private transient byte SteamID64Attempts;
//0x0110000100000000 - 76561197960265728
const SteamUID_Part1 = 76561197;
const SteamUID_Part2 = 960265728;
replication
{
reliable if ( bNetDirty && Role == Role_Authority )
BlameCounter, SteamID32;
}
function PostBeginPlay()
{
if ( Level.NetMode == NM_DedicatedServer )
GotoState('InitPRI');
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if ( SteamID32 > 0 && SteamID32 != ClientSteamID32 ) {
ClientSteamID32 = SteamID32;
SetSteamID32(SteamID32);
}
}
// UE2 doesn't support __int64 :(
final static function int SteamID64_to_32(string sid64)
{
local int a, billions;
if ( len(sid64) != 17 || left(sid64, 5) != "76561" )
return 0;
billions = int(left(sid64,8)) - SteamUID_Part1;
a = int(right(sid64,9));
if ( a < SteamUID_Part2 ) {
billions--;
a += 1000000000;
}
a -= SteamUID_Part2;
if ( billions > 4 || (billions == 4 && a >= 294967296) ) { // 2^32
log("Steam ID too high for 32-bit number: " $ sid64);
return 0; //
}
if ( billions > 2 || (billions == 2 && a >= 147483648) ) { // 2^31
// need to set highest (sign) bit to 1
billions -= 2;
a -= 147483648;
a += billions * 1000000000;
a = a | (1<<31);
}
else
a += billions * 1000000000;
return a;
}
final static function string SteamID32_to_64(int sid32)
{
local int a, billions;
local string result;
if ( sid32 < 0 ) {
// negative number mean highest int32 bit is 1 -> 2147483648
a = sid32 & 0x7FFFFFFF; // unset sign bit
billions = a / 1000000000;
a -= billions * 1000000000;
billions += SteamUID_Part1 + 2;
a += SteamUID_Part2 + 147483648;
if ( a > 1000000000 ) {
billions += a / 1000000000;
a = a % 1000000000;
}
}
else {
a = sid32;
billions = a / 1000000000;
a -= billions * 1000000000;
billions += SteamUID_Part1;
a += SteamUID_Part2;
if ( a > 1000000000 ) {
billions++;
a -= 1000000000;
}
}
result = string(a);
while ( len(result) < 9 )
result = "0" $ result;
result = string(billions) $ result;
return result;
}
final simulated function SetSteamID64(string value)
{
local int a;
a = SteamID64_to_32(value);
if ( a != 0 ) {
SteamID64 = value;
SteamID32 = a;
LoadHighlyDecorated();
}
//PlayerController(Owner).ClientMessage("SteamID64="$SteamID64 $ ", SteamID32="$SteamID32);
}
function simulated string GetSteamID64()
{
return SteamID64;
}
final simulated function SetSteamID32(int value)
{
SteamID64 = SteamID32_to_64(value);
SteamID32 = value;
LoadHighlyDecorated();
}
function simulated int GetSteamID32()
{
return SteamID32;
}
final simulated function LoadHighlyDecorated()
{
class'ScrnBalance'.static.GetHighlyDecorated(
SteamID32, Avatar, ClanIcon,
PreNameIcon, PrefixIconColor, PostNameIcon, PostfixIconColor,
TourneyPlayoffs, TourneyWins);
}
final static function ScrnCustomPRI FindMe(PlayerReplicationInfo PRI)
{
local LinkedReplicationInfo L;
if ( PRI == none )
return none;
for( L = PRI.CustomReplicationInfo; L != none; L = L.NextReplicationInfo ) {
if ( ScrnCustomPRI(L) != none )
return ScrnCustomPRI(L);
}
return none;
}
final simulated function bool IsTourneyMember()
{
return TourneyPlayoffs > 0;
}
final simulated function int GetPlayoffCount()
{
return TourneyPlayoffs;
}
final simulated function int GetTourneyWinCount()
{
return TourneyWins;
}
final simulated function material GetAvatar()
{
return Avatar;
}
final simulated function material GetClanIcon()
{
return ClanIcon;
}
final simulated function material GetSpecialIcon()
{
if ( Avatar != none )
return Avatar;
return ClanIcon;
}
final simulated function material GetPreNameIcon()
{
return PreNameIcon;
}
final simulated function material GetPostNameIcon()
{
return PostNameIcon;
}
state InitPRI
{
Begin:
while ( ++SteamID64Attempts <= 120 ) {
sleep(1); // give time to execute PostLogin() and set SteamID64
SteamID64 = PlayerController(Owner).GetPlayerIDHash();
if ( len(SteamID64) == 17 && left(SteamID64, 5) == "76561" ) {
SetSteamID64(SteamID64);
NetUpdateTime = Level.TimeSeconds - 1;
break;
}
}
GotoState('');
}
defaultproperties
{
bNetNotify=True
}

View file

@ -0,0 +1,313 @@
//for storing long numerical data that can't fit inside int
Class ScrnCustomProgressBytes extends SRCustomProgress
Abstract;
const CHR_MAX_VAL = 0x3FFFFFC0; //don't use 6 lowest and 2 highest bits in unicode character (16-bit)
const CHR_STEP = 0x40; // 0x40 = 1 >>> 6
const CHR_1ST_BIT = 6;
const CHR_CONTROL_VALUE = 1; // highest bits of a character must be "01"
const MAX_SIZE = 512;
// most left char contains Data[0], right - Data[Data.length-1]
var private string OldValueStr; // previous value that client received
var private string CurrentValueStr; // value to store in perks DB
var protected array<byte> Data;
var protected bool bFixedDataSize; //if true, Data.Length won't be modified (sublasses need to overrire InitData() to it)
var protected bool bReplicateDataToClients; // if true, CurrentValueStr will be always replicated to clients
//reason why CurrentValueStr has been updated
enum EValueSource
{
SRC_None,
SRC_External, // updated from outer source (e.g. perk DB)
SRC_Internal // updated from Data
};
var private transient EValueSource ValueSource;
enum EStringStoreMethod
{
SM_Hex, //store data as string representation of hex values (2 chars per byte, but data is human-readable)
SM_Unicode //store data inside unicode character (1 char per byte, but human will see crazy unicode chars instead of data)
};
var protected EStringStoreMethod StoreMethod;
replication
{
reliable if( bReplicateDataToClients && bNetOwner && ( bNetDirty || bNetInitial ) && Role==ROLE_Authority )
ValueSource, CurrentValueStr;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if ( Role < Role_Authority && OldValueStr != CurrentValueStr ) {
//log(GetItemName(String(name))$".PostNetReceive() OldValueStr="$OldValueStr $ " CurrentValueStr="$CurrentValueStr, 'ScrnBalance');
UpdateData();
OldValueStr = CurrentValueStr;
}
}
simulated function EValueSource GetValueSource()
{
return ValueSource;
}
simulated function PostBeginPlay()
{
super.PostBeginPlay();
InitData();
}
simulated function InitData();
simulated function string GetProgress()
{
return CurrentValueStr;
}
simulated function int GetProgressInt()
{
return 0;
}
simulated function string GetDisplayString()
{
return class'SRCustomProgress'.default.ProgressName; //Lazy modder! Kill him!! :)
}
function SetProgress( string S )
{
if ( Len(S) > MAX_SIZE) {
log("ScrnCustomProgressBytes: Passed string is longer than " $ String(MAX_SIZE), 'ScrnBalance');
S = left(S, MAX_SIZE); //trim long string
}
//log("SetProgress("$S$")", 'ScrnBalance');
CurrentValueStr = S;
ValueSource = SRC_External;
if ( bReplicateDataToClients ) {
NetUpdateTime = Level.TimeSeconds - 1; //send CurrentValueStr to clients
}
UpdateData();
}
function IncrementProgress( int Count );
static function String ByteToBin(byte AValue)
{
local int i;
local string s;
while ( i++ < 8 ) {
S = String(AValue & 1) $ S;
AValue = AValue >>> 1;
}
return s;
}
static function String ByteToHex(byte AValue, optional bool bAddPrefix)
{
local int i;
local string s,c;
local byte a;
while ( i++ < 2 ) {
a = AValue & 0xF;
if ( a < 10 )
c = chr(0x30 + a);
else
c = chr(0x41 + a-10);
S = c $ S;
AValue = AValue >>> 4;
}
if ( bAddPrefix )
S = "0x" $ S;
return S;
}
static function String IntToHex(int AValue, optional bool bAddPrefix)
{
local int i;
local string s,c;
local byte a;
while ( i++ < 8 ) {
a = AValue & 0xF;
if ( a < 10 )
c = chr(0x30 + a);
else
c = chr(0x41 + a-10);
S = c $ S;
AValue = AValue >>> 4;
}
if ( bAddPrefix )
S = "0x" $ S;
return S;
}
static function byte HexToByte(String S)
{
local int i, end, a;
local byte result;
if ( left(S, 2) ~= "0x" )
i = 2; //skip prefix
end = min(i + 2, len(S));
while ( i < end ) {
result = result << 4;
a = asc(mid(s, i, 1));
if ( a >= 0x30 && a <= 0x39 )
a -= 0x30; //digit
else if ( a >= 0x41 && a <= 0x46 )
a = a + 10 - 0x41; //A-F
else if ( a >= 0x61 && a <= 0x46 )
a = a + 10 - 0x61; //a-f
else
return 0; // illegal character
result = result | a;
i++;
}
return result;
}
static function LogBytes(array<byte> AValues)
{
local int i, a, count, c_len;
local string i_str;
count = AValues.Length;
c_len=len(count);
for ( i=0; i < count; ++i) {
i_str = string(i+1);
while ( len(i_str) < c_len )
i_str = "0" $ i_str;
a = AValues[i];
log("#"$i_str$"/"$count$":" @ ByteToBin(a) @ ByteToHex(a,true) @ a, 'ScrnBalance');
}
}
simulated function LogValues()
{
log("ScrnCustomProgressBytes: Value of '"$CurrentValueStr$"':", 'ScrnBalance');
LogBytes(Data);
}
static function StringToValues(string AString, out array<byte> AValues)
{
if ( default.StoreMethod == SM_Unicode)
UnicodeStringToValues(AString, AValues);
else
HexStringToValues(AString, AValues);
}
static function UnicodeStringToValues(string AString, out array<byte> AValues)
{
local int i, count, val;
local string c;
if ( !default.bFixedDataSize )
AValues.Length = len(AString);
count = min(len(AString), AValues.Length);
for ( i = 0; i < count; ++i ) {
c = mid(AString,i,1);
val = asc(c) >>> CHR_1ST_BIT;
if ( val>>>8 != CHR_CONTROL_VALUE ) {
// in case server admin manually edits stat table and screws the data
log("ScrnCustomProgressBytes: Illegal Character #"$i$" '"$c$"' ("$asc(c)$") in string '"$AString$"'", 'ScrnBalance');
}
else {
val = val & 0xFF; //clear a highest byte;
AValues[i] = val;
}
}
}
static function HexStringToValues(string AString, out array<byte> AValues)
{
local int i, count;
if ( !default.bFixedDataSize )
AValues.Length = len(AString)/2; //2 chars per one byte
count = min(len(AString)/2, AValues.Length);
for ( i = 0; i < count; ++i ) {
AValues[i] = HexToByte(mid(AString,i*2,2));
}
}
static function string ValuesToString(array<byte> AValues)
{
if ( default.StoreMethod == SM_Unicode)
return ValuesToUnicodeString(AValues);
else
return ValuesToHexString(AValues);
}
static function string ValuesToUnicodeString(array<byte> AValues)
{
local int i;
local string s;
for ( i = 0; i < AValues.length; ++i ) {
// add contro value, shift left 8 bits, fill data, shift dummy bits, which fill with random numbers
s $= chr((CHR_CONTROL_VALUE<<8 | AValues[i])<<CHR_1ST_BIT | rand(0x3F));
}
return s;
}
static function string ValuesToHexString(array<byte> AValues)
{
local int i;
local string s;
for ( i = 0; i < AValues.length; ++i ) {
s $= ByteToHex(AValues[i], false);
}
return s;
}
simulated function UpdateData()
{
StringToValues(CurrentValueStr, Data);
//LogValues();
}
//clients can't update String, they just receive it from server
function UpdateValueString()
{
CurrentValueStr = ValuesToString(Data);
ValueSource = SRC_Internal;
if ( bReplicateDataToClients )
NetUpdateTime = Level.TimeSeconds - 1; //send CurrentValueStr to clients
}
/*
protected function FillWithTestData(int ValueCount)
{
local int i;
Data.Length = ValueCount;
for ( i = 0; i < ValueCount; ++i ) {
Data[i] = i;
}
UpdateString();
}
*/
defaultproperties
{
bNetNotify=True
}

View file

@ -0,0 +1,137 @@
/**
* Base class for all ScrN shotgun bulelts.
* Adjusted MaxPenetrations to be really max penetration count (off-perk)
* Added feature to make additional penetration damage reduction when hitting specific zeds
*
* @author PooSH, 2012
*/
class ScrnCustomShotgunBullet extends ShotgunBullet
abstract;
var() float BigZedPenDmgReduction; // Additional penetration damage reduction after hitting big zeds. 0.5 = 50% dmg. red.
var() int BigZedMinHealth; // If zed's base Health >= this value, zed counts as Big
var() float MediumZedPenDmgReduction; // Additional penetration damage reduction after hitting medium-size zeds. 0.5 = 50% dmg. red.
var() int MediumZedMinHealth; // If zed's base Health >= this value, zed counts as Medium-size
var String StaticMeshRef;
var String AmbientSoundRef;
static function PreloadAssets()
{
if ( default.AmbientSoundRef != "" )
default.AmbientSound = sound(DynamicLoadObject(default.AmbientSoundRef, class'Sound', true));
if ( default.StaticMeshRef != "" )
UpdateDefaultStaticMesh(StaticMesh(DynamicLoadObject(default.StaticMeshRef, class'StaticMesh', true)));
}
static function bool UnloadAssets()
{
if ( default.AmbientSoundRef != "" )
default.AmbientSound = none;
if ( default.StaticMeshRef != "" )
UpdateDefaultStaticMesh(none);
return true;
}
simulated function ProcessTouch (Actor Other, vector HitLocation)
{
local vector X;
local Vector TempHitLocation, HitNormal;
local array<int> HitPoints;
local KFPlayerReplicationInfo KFPRI;
local KFPawn HitPawn;
local Pawn Victim;
local KFMonster KFM;
if ( Other == none || Other == Instigator || Other.Base == Instigator || !Other.bBlockHitPointTraces )
return;
X = Vector(Rotation);
if( Instigator != none && ROBulletWhipAttachment(Other) != none ) {
// we touched player's auxilary collision cylinder, not let's trace to the player himself
// Other.Base = KFPawn
if( Other.Base == none || Other.Base.bDeleteMe )
return;
Other = Instigator.HitPointTrace(TempHitLocation, HitNormal, HitLocation + (200 * X), HitPoints, HitLocation,, 1);
if( Other == none || HitPoints.Length == 0 || Other.bDeleteMe )
return; // bullet didn't hit a pawn
HitPawn = KFPawn(Other);
if ( HitPawn != none ) {
HitPawn.ProcessLocationalDamage(Damage, Instigator, TempHitLocation, MomentumTransfer * Normal(Velocity), MyDamageType,HitPoints);
}
}
else {
if ( ExtendedZCollision(Other) != none)
Victim = Pawn(Other.Owner); // ExtendedZCollision is attached to KFMonster
else if ( Pawn(Other) != none )
Victim = Pawn(Other);
KFM = KFMonster(Victim);
if ( Victim != none && Victim.IsHeadShot(HitLocation, X, 1.0))
Victim.TakeDamage(Damage * HeadShotDamageMult, Instigator, HitLocation, MomentumTransfer * Normal(Velocity), MyDamageType);
else
Other.TakeDamage(Damage, Instigator, HitLocation, MomentumTransfer * Normal(Velocity), MyDamageType);
}
if ( Instigator != none )
KFPRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo);
if ( KFPRI != none && KFPRI.ClientVeteranSkill != none )
PenDamageReduction = KFPRI.ClientVeteranSkill.static.GetShotgunPenetrationDamageMulti(KFPRI,default.PenDamageReduction);
else
PenDamageReduction = default.PenDamageReduction;
// loose penetrational damage after hitting specific zeds -- PooSH
if ( KFM != none)
PenDamageReduction *= ZedPenDamageReduction(KFM);
Damage *= PenDamageReduction; // Keep going, but lose effectiveness each time.
// if we've struck through more than the max number of foes, destroy.
// MaxPenetrations now really means number of max penetration off-perk -- PooSH
if ( Damage / default.Damage < (default.PenDamageReduction ** MaxPenetrations) + 0.0001 )
Destroy();
else {
speed = VSize(Velocity);
if( Speed < (default.Speed * 0.25) )
Destroy();
}
}
/**
* Further damage reduction after hitting a specific zed
* @param Monster Zed that took damage
* @return Further penetration damage reduction. Doesn't affect current Monster!
* 1.0 - no additional penetration damage reduction
* 0.75 - 25% additional penetration damage reduction
*/
simulated function float ZedPenDamageReduction(KFMonster Monster)
{
if ( Monster == none )
return 1.0;
if ( Monster.default.Health >= BigZedMinHealth )
return BigZedPenDmgReduction;
else if ( Monster.default.Health >= MediumZedMinHealth )
return MediumZedPenDmgReduction;
return 1.0;
}
defaultproperties
{
BigZedPenDmgReduction=0.500000
BigZedMinHealth=1000
MediumZedPenDmgReduction=0.750000
MediumZedMinHealth=500
MaxPenetrations=3
PenDamageReduction=0.700000
}

View file

@ -0,0 +1,118 @@
Class ScrnCustomWeaponLink extends LinkedReplicationInfo;
var class <ScrnVeterancyTypes> Perk;
var class <KFWeapon> WeaponClass;
var bool bWeapon, bDiscount, bFire, bFireAlt, bAmmo, bAmmoAlt;
var bool bOverrideDamType, bOverrideDamTypeAlt, bSpecial;
var int ForcePrice;
var transient bool bInitReplicationReceived;
replication
{
reliable if ( Role == ROLE_Authority )
Perk, WeaponClass, bWeapon, bDiscount, bFire, bFireAlt, bAmmo, bAmmoAlt,
bOverrideDamType, bOverrideDamTypeAlt, bSpecial,
ForcePrice;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
// Can PostNetReceive() be called before PostNetBeginPlay() in ut2k4 engine either?
if ( bInitReplicationReceived && Role < ROLE_Authority ) {
LoadWeaponBonuses();
}
}
simulated function PostNetBeginPlay()
{
super.PostNetBeginPlay();
bInitReplicationReceived = true;
if ( Role < ROLE_Authority ) {
LoadWeaponBonuses();
}
}
simulated function LoadWeaponBonuses()
{
local class<WeaponFire> WF;
local class<KFWeaponDamageType> DT;
local class<KFWeaponPickup> WP;
if ( Perk == none || WeaponClass == none )
return;
if ( bWeapon )
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedWeapons, WeaponClass);
if ( bSpecial )
Perk.static.ClassAddToArrayUnique(Perk.default.SpecialWeapons, WeaponClass);
if ( bDiscount )
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedPickups, WeaponClass.default.PickupClass);
WP = class<KFWeaponPickup>(WeaponClass.default.PickupClass);
if ( ForcePrice > 0 && WP != none )
WP.default.Cost = ForcePrice;
// Primary fire
WF = WeaponClass.default.FireModeClass[0];
if ( WF != none && WF != Class'KFMod.NoFire' ) {
if ( bAmmo ) {
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedAmmo, WF.default.AmmoClass);
}
if ( bOverrideDamType && Perk.default.DefaultDamageType != none ) {
//replace weapon perk index
class<KFWeaponPickup>(WeaponClass.default.PickupClass).default.CorrespondingPerkIndex = Perk.default.PerkIndex;
if ( bFire || Perk.default.DefaultDamageTypeNoBonus == none )
DT = Perk.default.DefaultDamageType;
else
DT = Perk.default.DefaultDamageTypeNoBonus;
//overriding damage types to allow leveling up
if ( WF.default.ProjectileClass != none )
WF.default.ProjectileClass.default.MyDamageType = DT;
if ( class<InstantFire>(WF) != none )
class<InstantFire>(WF).default.DamageType = DT;
}
else if ( bFire ) {
if ( WF.default.ProjectileClass != none )
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedDamTypes, WF.default.ProjectileClass.default.MyDamageType);
if ( class<InstantFire>(WF) != none )
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedDamTypes, class<InstantFire>(WF).default.DamageType);
}
}
// Alternate Fire
WF = WeaponClass.default.FireModeClass[1];
if ( WF != none && WF != Class'KFMod.NoFire' ) {
if ( bAmmoAlt ) {
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedAmmo, WF.default.AmmoClass);
}
if ( bOverrideDamTypeAlt && Perk.default.DefaultDamageType != none ) {
if ( bFireAlt || Perk.default.DefaultDamageTypeNoBonus == none )
DT = Perk.default.DefaultDamageType;
else
DT = Perk.default.DefaultDamageTypeNoBonus;
//overriding damage types to allow leveling up
if ( WF.default.ProjectileClass != none )
WF.default.ProjectileClass.default.MyDamageType = DT;
if ( class<InstantFire>(WF) != none )
class<InstantFire>(WF).default.DamageType = DT;
}
else if ( bFireAlt ) {
if ( WF.default.ProjectileClass != none )
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedDamTypes, WF.default.ProjectileClass.default.MyDamageType);
if ( class<InstantFire>(WF) != none )
Perk.static.ClassAddToArrayUnique(Perk.default.PerkedDamTypes, class<InstantFire>(WF).default.DamageType);
}
}
Log("Custom weapon" @ String(WeaponClass) @ "loaded for " @ String(Perk) @ "perk.", 'ScrnBalance');
}
defaultproperties
{
}

View file

@ -0,0 +1,18 @@
class ScrnDamTypeAK47AssaultRifle extends DamTypeAK47AssaultRifle
abstract;
// Award also Shiver kills with 2x Stalker progress
// v4.59 - count only 1 kill from now on, because new version of Shiver.se calls
// AwardKill() twice: for the decapitator and for the killer
static function AwardKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed )
{
if( Killed.IsA('ZombieShiver') )
KFStatsAndAchievements.AddStalkerKill();
else
super.AwardKill(KFStatsAndAchievements, Killer, Killed);
}
defaultproperties
{
WeaponClass=Class'ScrnBalanceSrv.ScrnAK47AssaultRifle'
}

View file

@ -0,0 +1,18 @@
class ScrnDamTypeBullpup extends DamTypeBullpup
abstract;
// Award also Shiver kills with 2x Stalker progress
// v4.59 - count only 1 kill from now on, because new version of Shiver.se calls
// AwardKill() twice: for the decapitator and for the killer
static function AwardKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed )
{
if( Killed.IsA('ZombieShiver') )
KFStatsAndAchievements.AddStalkerKill();
else
super.AwardKill(KFStatsAndAchievements, Killer, Killed);
}
defaultproperties
{
WeaponClass=Class'ScrnBalanceSrv.ScrnBullpup'
}

View file

@ -0,0 +1,6 @@
class ScrnDamTypeChainsawAlt extends DamTypeChainsaw;
defaultproperties
{
HeadShotDamageMult=1.200000
}

View file

@ -0,0 +1,6 @@
class ScrnDamTypeCommando extends ScrnDamTypeCommandoBase
abstract;
defaultproperties
{
}

View file

@ -0,0 +1,24 @@
class ScrnDamTypeCommandoBase extends KFProjectileWeaponDamageType
abstract;
static function AwardKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed )
{
if( Killed.IsA('ZombieStalker') || Killed.IsA('ZombieShiver') )
KFStatsAndAchievements.AddStalkerKill();
}
static function AwardDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount)
{
KFStatsAndAchievements.AddBullpupDamage(Amount);
}
defaultproperties
{
DeathString="%k killed %o (Assault Rifle)."
FemaleSuicide="%o shot herself in the foot."
MaleSuicide="%o shot himself in the foot."
bRagdollBullet=True
KDamageImpulse=1500.000000
KDeathVel=110.000000
KDeathUpKick=2.000000
}

View file

@ -0,0 +1,6 @@
class ScrnDamTypeCrossbuzzsaw extends DamTypeCrossbuzzsaw;
defaultproperties
{
WeaponClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsaw'
}

View file

@ -0,0 +1,42 @@
class ScrnDamTypeDeagle extends DamTypeDeagle;
static function AwardKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed )
{
local SRStatsBase stats;
// do not count kills of decapitated specimens - those are counted in ScoredHeadshot()
if ( Killed != none && Killed.bDecapitated )
return;
stats = SRStatsBase(KFStatsAndAchievements);
if( stats !=None && stats.Rep!=None )
stats.Rep.ProgressCustomValue(Class'ScrnBalanceSrv.ScrnPistolKillProgress',1);
}
static function ScoredHeadshot(KFSteamStatsAndAchievements KFStatsAndAchievements, class<KFMonster> MonsterClass, bool bLaserSightedM14EBRKill)
{
local SRStatsBase stats;
if ( KFStatsAndAchievements != none ) {
if ( Default.bSniperWeapon )
KFStatsAndAchievements.AddHeadshotKill(bLaserSightedM14EBRKill);
stats = SRStatsBase(KFStatsAndAchievements);
if( stats !=None && stats.Rep!=None )
stats.Rep.ProgressCustomValue(Class'ScrnBalanceSrv.ScrnPistolKillProgress',1);
}
}
static function AwardDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount)
{
local SRStatsBase stats;
stats = SRStatsBase(KFStatsAndAchievements);
if( stats !=None && stats.Rep!=None )
stats.Rep.ProgressCustomValue(Class'ScrnBalanceSrv.ScrnPistolDamageProgress',Amount);
}
defaultproperties
{
WeaponClass=Class'ScrnBalanceSrv.ScrnDeagle'
}

View file

@ -0,0 +1,6 @@
class ScrnDamTypeDefaultDemoBase extends DamTypeLAW
abstract;
defaultproperties
{
}

View file

@ -0,0 +1,6 @@
class ScrnDamTypeDefaultFirebugBase extends DamTypeBurned
abstract;
defaultproperties
{
}

View file

@ -0,0 +1,6 @@
class ScrnDamTypeDefaultGunslinger extends ScrnDamTypeDefaultGunslingerBase
abstract;
defaultproperties
{
}

View file

@ -0,0 +1,35 @@
class ScrnDamTypeDefaultGunslingerBase extends KFProjectileWeaponDamageType
abstract;
static function AwardKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed )
{
local SRStatsBase stats;
stats = SRStatsBase(KFStatsAndAchievements);
if( stats !=None && stats.Rep!=None ) {
stats.Rep.ProgressCustomValue(Class'ScrnBalanceSrv.ScrnPistolKillProgress',1);
}
}
static function AwardDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount)
{
local SRStatsBase stats;
stats = SRStatsBase(KFStatsAndAchievements);
if( stats !=None && stats.Rep!=None )
stats.Rep.ProgressCustomValue(Class'ScrnBalanceSrv.ScrnPistolDamageProgress',Amount);
}
defaultproperties
{
DeathString="%k killed %o (Pistol)."
FemaleSuicide="%o shot herself in the foot."
MaleSuicide="%o shot himself in the foot."
bRagdollBullet=True
bBulletHit=True
FlashFog=(X=600.000000)
KDamageImpulse=3500.000000
KDeathVel=175.000000
KDeathUpKick=15.000000
VehicleDamageScaling=0.800000
}

Some files were not shown because too many files have changed in this diff Show more