Prepare fixtures
This commit is contained in:
parent
797e5ea192
commit
9c94356263
6021 changed files with 722805 additions and 22 deletions
186
kf_sources/ScrnBalanceSrv/Classes/Ach.uc
Normal file
186
kf_sources/ScrnBalanceSrv/Classes/Ach.uc
Normal 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"
|
||||
}
|
||||
225
kf_sources/ScrnBalanceSrv/Classes/AchMaps.uc
Normal file
225
kf_sources/ScrnBalanceSrv/Classes/AchMaps.uc
Normal 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"
|
||||
}
|
||||
25
kf_sources/ScrnBalanceSrv/Classes/AchObjMaps.uc
Normal file
25
kf_sources/ScrnBalanceSrv/Classes/AchObjMaps.uc
Normal 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"
|
||||
}
|
||||
101
kf_sources/ScrnBalanceSrv/Classes/BaronsGame.uc
Normal file
101
kf_sources/ScrnBalanceSrv/Classes/BaronsGame.uc
Normal 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"
|
||||
}
|
||||
49
kf_sources/ScrnBalanceSrv/Classes/BlueWhisp.uc
Normal file
49
kf_sources/ScrnBalanceSrv/Classes/BlueWhisp.uc
Normal 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)
|
||||
}
|
||||
9
kf_sources/ScrnBalanceSrv/Classes/DamTypeEnemyBase.uc
Normal file
9
kf_sources/ScrnBalanceSrv/Classes/DamTypeEnemyBase.uc
Normal 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"
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/DamTypeSudDeath.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/DamTypeSudDeath.uc
Normal 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
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
20
kf_sources/ScrnBalanceSrv/Classes/DoomMusicTrigger.uc
Normal file
20
kf_sources/ScrnBalanceSrv/Classes/DoomMusicTrigger.uc
Normal 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
|
||||
}
|
||||
13
kf_sources/ScrnBalanceSrv/Classes/FscGame.uc
Normal file
13
kf_sources/ScrnBalanceSrv/Classes/FscGame.uc
Normal 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"
|
||||
}
|
||||
331
kf_sources/ScrnBalanceSrv/Classes/FtgGame.uc
Normal file
331
kf_sources/ScrnBalanceSrv/Classes/FtgGame.uc
Normal 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"
|
||||
}
|
||||
221
kf_sources/ScrnBalanceSrv/Classes/FtgHUD.uc
Normal file
221
kf_sources/ScrnBalanceSrv/Classes/FtgHUD.uc
Normal 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!"
|
||||
}
|
||||
49
kf_sources/ScrnBalanceSrv/Classes/GreenWhisp.uc
Normal file
49
kf_sources/ScrnBalanceSrv/Classes/GreenWhisp.uc
Normal 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)
|
||||
}
|
||||
87
kf_sources/ScrnBalanceSrv/Classes/ReducedGrenadeTrail.uc
Normal file
87
kf_sources/ScrnBalanceSrv/Classes/ReducedGrenadeTrail.uc
Normal 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'
|
||||
|
||||
}
|
||||
6
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Ammo.uc
Normal file
6
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Ammo.uc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnAA12Ammo extends AA12Ammo;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
PickupClass=Class'ScrnBalanceSrv.ScrnAA12AmmoPickup'
|
||||
}
|
||||
6
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12AmmoPickup.uc
Normal file
6
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12AmmoPickup.uc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnAA12AmmoPickup extends AA12AmmoPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnAA12Ammo'
|
||||
}
|
||||
232
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12AutoShotgun.uc
Normal file
232
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12AutoShotgun.uc
Normal 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"
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Bullet.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Bullet.uc
Normal 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
|
||||
}
|
||||
69
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Fire.uc
Normal file
69
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Fire.uc
Normal 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'
|
||||
}
|
||||
9
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Pickup.uc
Normal file
9
kf_sources/ScrnBalanceSrv/Classes/ScrnAA12Pickup.uc
Normal 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'
|
||||
}
|
||||
108
kf_sources/ScrnBalanceSrv/Classes/ScrnAK47AssaultRifle.uc
Normal file
108
kf_sources/ScrnBalanceSrv/Classes/ScrnAK47AssaultRifle.uc
Normal 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"
|
||||
}
|
||||
6
kf_sources/ScrnBalanceSrv/Classes/ScrnAK47Fire.uc
Normal file
6
kf_sources/ScrnBalanceSrv/Classes/ScrnAK47Fire.uc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnAK47Fire extends AK47Fire;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
DamageType=Class'ScrnBalanceSrv.ScrnDamTypeAK47AssaultRifle'
|
||||
}
|
||||
8
kf_sources/ScrnBalanceSrv/Classes/ScrnAK47Pickup.uc
Normal file
8
kf_sources/ScrnBalanceSrv/Classes/ScrnAK47Pickup.uc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class ScrnAK47Pickup extends AK47Pickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
ItemName="AK-47 SE"
|
||||
ItemShortName="AK-47 SE"
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnAK47AssaultRifle'
|
||||
}
|
||||
1083
kf_sources/ScrnBalanceSrv/Classes/ScrnAchHandler.uc
Normal file
1083
kf_sources/ScrnBalanceSrv/Classes/ScrnAchHandler.uc
Normal file
File diff suppressed because it is too large
Load diff
392
kf_sources/ScrnBalanceSrv/Classes/ScrnAchHandlerBase.uc
Normal file
392
kf_sources/ScrnBalanceSrv/Classes/ScrnAchHandlerBase.uc
Normal 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
|
||||
{
|
||||
}
|
||||
224
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievementEarnedMsg.uc
Normal file
224
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievementEarnedMsg.uc
Normal 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
|
||||
}
|
||||
804
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievements.uc
Normal file
804
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievements.uc
Normal 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
|
||||
}
|
||||
196
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievementsList.uc
Normal file
196
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievementsList.uc
Normal 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
|
||||
}
|
||||
31
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievementsListBox.uc
Normal file
31
kf_sources/ScrnBalanceSrv/Classes/ScrnAchievementsListBox.uc
Normal 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"
|
||||
}
|
||||
184
kf_sources/ScrnBalanceSrv/Classes/ScrnAmmoPickup.uc
Normal file
184
kf_sources/ScrnBalanceSrv/Classes/ScrnAmmoPickup.uc
Normal 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)
|
||||
}
|
||||
10
kf_sources/ScrnBalanceSrv/Classes/ScrnAxe.uc
Normal file
10
kf_sources/ScrnBalanceSrv/Classes/ScrnAxe.uc
Normal 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"
|
||||
}
|
||||
7
kf_sources/ScrnBalanceSrv/Classes/ScrnAxeFire.uc
Normal file
7
kf_sources/ScrnBalanceSrv/Classes/ScrnAxeFire.uc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
class ScrnAxeFire extends AxeFire;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
WideDamageMinHitAngle=0.750000
|
||||
bWaitForRelease=True
|
||||
}
|
||||
7
kf_sources/ScrnBalanceSrv/Classes/ScrnAxeFireB.uc
Normal file
7
kf_sources/ScrnBalanceSrv/Classes/ScrnAxeFireB.uc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
class ScrnAxeFireB extends AxeFireB;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
WideDamageMinHitAngle=0.000000
|
||||
bWaitForRelease=True
|
||||
}
|
||||
9
kf_sources/ScrnBalanceSrv/Classes/ScrnAxePickup.uc
Normal file
9
kf_sources/ScrnBalanceSrv/Classes/ScrnAxePickup.uc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class ScrnAxePickup extends AxePickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
cost=200
|
||||
ItemName="Axe SE"
|
||||
ItemShortName="Axe SE"
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnAxe'
|
||||
}
|
||||
3544
kf_sources/ScrnBalanceSrv/Classes/ScrnBalance.uc
Normal file
3544
kf_sources/ScrnBalanceSrv/Classes/ScrnBalance.uc
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,8 @@
|
|||
class ScrnBalancePersistence extends Object
|
||||
Config(ScrnInternal);
|
||||
|
||||
var config byte Difficulty;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
931
kf_sources/ScrnBalanceSrv/Classes/ScrnBalanceVoting.uc
Normal file
931
kf_sources/ScrnBalanceSrv/Classes/ScrnBalanceVoting.uc
Normal 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
|
||||
}
|
||||
8
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliAmmo.uc
Normal file
8
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliAmmo.uc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class ScrnBenelliAmmo extends BenelliAmmo;
|
||||
|
||||
//duplicated by goldenbenelliammo
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
AmmoPickupAmount=12
|
||||
}
|
||||
53
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliAttachment.uc
Normal file
53
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliAttachment.uc
Normal 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"
|
||||
}
|
||||
27
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliBullet.uc
Normal file
27
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliBullet.uc
Normal 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'
|
||||
}
|
||||
80
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliFire.uc
Normal file
80
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliFire.uc
Normal 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
|
||||
}
|
||||
10
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliPickup.uc
Normal file
10
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliPickup.uc
Normal 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'
|
||||
}
|
||||
329
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliShotgun.uc
Normal file
329
kf_sources/ScrnBalanceSrv/Classes/ScrnBenelliShotgun.uc
Normal 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"
|
||||
}
|
||||
71
kf_sources/ScrnBalanceSrv/Classes/ScrnBlamedMsg.uc
Normal file
71
kf_sources/ScrnBalanceSrv/Classes/ScrnBlamedMsg.uc
Normal 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
|
||||
}
|
||||
228
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStick.uc
Normal file
228
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStick.uc
Normal 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"
|
||||
}
|
||||
32
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickAltFire.uc
Normal file
32
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickAltFire.uc
Normal 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'
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickBullet.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickBullet.uc
Normal 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'
|
||||
}
|
||||
32
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickFire.uc
Normal file
32
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickFire.uc
Normal 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'
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickPickup.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBoomStickPickup.uc
Normal 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'
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpup.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpup.uc
Normal 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"
|
||||
}
|
||||
7
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpupAmmo.uc
Normal file
7
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpupAmmo.uc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
class ScrnBullpupAmmo extends BullpupAmmo;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
InitialAmount=200
|
||||
PickupClass=Class'ScrnBalanceSrv.ScrnBullpupAmmoPickup'
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnBullpupAmmoPickup extends BullpupAmmoPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnBullpupAmmo'
|
||||
}
|
||||
131
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpupFire.uc
Normal file
131
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpupFire.uc
Normal 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'
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpupPickup.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnBullpupPickup.uc
Normal 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'
|
||||
}
|
||||
323
kf_sources/ScrnBalanceSrv/Classes/ScrnBurnMech.uc
Normal file
323
kf_sources/ScrnBalanceSrv/Classes/ScrnBurnMech.uc
Normal 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"
|
||||
}
|
||||
501
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuInvList.uc
Normal file
501
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuInvList.uc
Normal 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"
|
||||
}
|
||||
12
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuInvListBox.uc
Normal file
12
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuInvListBox.uc
Normal 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
|
||||
{
|
||||
}
|
||||
816
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuSaleList.uc
Normal file
816
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuSaleList.uc
Normal 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
|
||||
}
|
||||
12
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuSaleListBox.uc
Normal file
12
kf_sources/ScrnBalanceSrv/Classes/ScrnBuyMenuSaleListBox.uc
Normal 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
|
||||
{
|
||||
}
|
||||
70
kf_sources/ScrnBalanceSrv/Classes/ScrnCashPickup.uc
Normal file
70
kf_sources/ScrnBalanceSrv/Classes/ScrnCashPickup.uc
Normal 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
|
||||
}
|
||||
359
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsaw.uc
Normal file
359
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsaw.uc
Normal 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"
|
||||
}
|
||||
49
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawAltFire.uc
Normal file
49
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawAltFire.uc
Normal 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'
|
||||
}
|
||||
12
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawAmmo.uc
Normal file
12
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawAmmo.uc
Normal 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"
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
class ScrnChainsawAmmoPickup extends ChainsawAmmoPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
AmmoAmount=105
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnChainsawAmmo'
|
||||
PickupMessage="ML of Gasoline"
|
||||
StaticMesh=StaticMesh'KillingFloorStatics.FT_AmmoMesh'
|
||||
}
|
||||
53
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawFire.uc
Normal file
53
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawFire.uc
Normal 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
|
||||
}
|
||||
13
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawPickup.uc
Normal file
13
kf_sources/ScrnBalanceSrv/Classes/ScrnChainsawPickup.uc
Normal 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."
|
||||
}
|
||||
13
kf_sources/ScrnBalanceSrv/Classes/ScrnClaymoreSword.uc
Normal file
13
kf_sources/ScrnBalanceSrv/Classes/ScrnClaymoreSword.uc
Normal 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"
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnClaymoreSwordFire.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnClaymoreSwordFire.uc
Normal 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
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class ScrnClaymoreSwordFireB extends ClaymoreSwordFireB;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
11
kf_sources/ScrnBalanceSrv/Classes/ScrnClaymoreSwordPickup.uc
Normal file
11
kf_sources/ScrnBalanceSrv/Classes/ScrnClaymoreSwordPickup.uc
Normal 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'
|
||||
}
|
||||
870
kf_sources/ScrnBalanceSrv/Classes/ScrnClientPerkRepLink.uc
Normal file
870
kf_sources/ScrnBalanceSrv/Classes/ScrnClientPerkRepLink.uc
Normal 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
|
||||
}
|
||||
13
kf_sources/ScrnBalanceSrv/Classes/ScrnCombatVestPickup.uc
Normal file
13
kf_sources/ScrnBalanceSrv/Classes/ScrnCombatVestPickup.uc
Normal 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"
|
||||
}
|
||||
8
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbow.uc
Normal file
8
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbow.uc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class ScrnCrossbow extends Crossbow;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
FireModeClass(0)=Class'ScrnBalanceSrv.ScrnCrossbowFire'
|
||||
PickupClass=Class'ScrnBalanceSrv.ScrnCrossbowPickup'
|
||||
ItemName="Compound Crossbow SE"
|
||||
}
|
||||
35
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbowArrow.uc
Normal file
35
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbowArrow.uc
Normal 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
|
||||
}
|
||||
7
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbowFire.uc
Normal file
7
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbowFire.uc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
class ScrnCrossbowFire extends CrossbowFire;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
ProjSpawnOffset=(X=0.000000)
|
||||
ProjectileClass=Class'ScrnBalanceSrv.ScrnCrossbowArrow'
|
||||
}
|
||||
10
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbowPickup.uc
Normal file
10
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbowPickup.uc
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
class ScrnCrossbowPickup extends CrossbowPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
cost=1600
|
||||
AmmoCost=120
|
||||
ItemName="Crossbow SE"
|
||||
ItemShortName="Crossbow SE"
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnCrossbow'
|
||||
}
|
||||
9
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbuzzsaw.uc
Normal file
9
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbuzzsaw.uc
Normal 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"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
class ScrnCrossbuzzsawAmmo extends CrossbuzzsawAmmo;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
AmmoPickupAmount=2
|
||||
MaxAmmo=20
|
||||
PickupClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawPickup'
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnCrossbuzzsawAmmoPickup extends CrossbuzzsawAmmoPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnCrossbuzzsawAmmo'
|
||||
}
|
||||
218
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbuzzsawBlade.uc
Normal file
218
kf_sources/ScrnBalanceSrv/Classes/ScrnCrossbuzzsawBlade.uc
Normal 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
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
class ScrnCrossbuzzsawFire extends CrossbuzzsawFire;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
AmmoClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawAmmo'
|
||||
ProjectileClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsawBlade'
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
class ScrnCrossbuzzsawPickup extends CrossbuzzsawPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
Weight=9.000000
|
||||
ItemName="Buzzsaw Bow SE"
|
||||
ItemShortName="Buzzsaw Bow SE"
|
||||
InventoryType=Class'ScrnBalanceSrv.ScrnCrossbuzzsaw'
|
||||
}
|
||||
215
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomPRI.uc
Normal file
215
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomPRI.uc
Normal 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
|
||||
}
|
||||
313
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomProgressBytes.uc
Normal file
313
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomProgressBytes.uc
Normal 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
|
||||
}
|
||||
137
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomShotgunBullet.uc
Normal file
137
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomShotgunBullet.uc
Normal 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
|
||||
}
|
||||
118
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomWeaponLink.uc
Normal file
118
kf_sources/ScrnBalanceSrv/Classes/ScrnCustomWeaponLink.uc
Normal 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
|
||||
{
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
18
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeBullpup.uc
Normal file
18
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeBullpup.uc
Normal 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'
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnDamTypeChainsawAlt extends DamTypeChainsaw;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
HeadShotDamageMult=1.200000
|
||||
}
|
||||
6
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeCommando.uc
Normal file
6
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeCommando.uc
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnDamTypeCommando extends ScrnDamTypeCommandoBase
|
||||
abstract;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
24
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeCommandoBase.uc
Normal file
24
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeCommandoBase.uc
Normal 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
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnDamTypeCrossbuzzsaw extends DamTypeCrossbuzzsaw;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
WeaponClass=Class'ScrnBalanceSrv.ScrnCrossbuzzsaw'
|
||||
}
|
||||
42
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeDeagle.uc
Normal file
42
kf_sources/ScrnBalanceSrv/Classes/ScrnDamTypeDeagle.uc
Normal 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'
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnDamTypeDefaultDemoBase extends DamTypeLAW
|
||||
abstract;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnDamTypeDefaultFirebugBase extends DamTypeBurned
|
||||
abstract;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class ScrnDamTypeDefaultGunslinger extends ScrnDamTypeDefaultGunslingerBase
|
||||
abstract;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
}
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue