class NicePack extends Mutator dependson(NiceStorageServer) config(NicePack); // Should we scale health off all zeds to 6-player level? var config bool bScaleZedHealth; // Should we replace all pickups with their Nice versions when available? var config bool bReplacePickups; // Settings for initial trader var config bool bInitialTrader; // Use initial trader system? var config bool bStillDuringInitTrader; // Force players to stand still during initial trader var config int initialTraderTime; // How much time should be allowed for initial trade? // Progressive dosh config var config bool bUseProgresiveCash; // Use progressive dosh system? var config array waveCash; var config float lateMultiplier; // Experience-conversion controlling variables var config bool bConvertExp; // Should we even convert old exp into a new one? var config float vetFieldMedicExpCost; // Amount of exp per HP healed var config float vetFieldMedicDmgExpCost; // Amount of exp per 1 medic damage var config float vetSharpHeadshotExpCost; // Amount of exp per head-shot var config float vetSupportDamageExpCost; // Amount of exp per 1 shotgun damage var config float vetCommandoDamageExpCost; // Amount of exp per 1 assault rifle damage var config float vetDemoDamageExpCost; // Amount of exp per 1 explosive damage var config float vetZerkDamageExpCost; // Amount of exp per 1 melee damage var config float vetHeavyMGDamageExpCost; // Amount of exp per 1 heavy machine gun damage var config float vetGunslingerKillExpCost; // Amount of exp per 1 assault rifle damage // Allow changing skills at any time var config bool bAlwaysAllowSkillChange; // Variables for controlling how zeds spawn var config float minSpawnRate, maxSpawnRate; // Minimum and maximum allowed spawn rate var config int minimalSpawnDistance; // Minimal distance between ZedVolume and players that should allow for zeds to spawn // FF voting - related settings var config bool bOneFFIncOnly; // Option that only allows one FF increase per game var config bool bNoLateFFIncrease; // Disables FF increase through voting after 1st wave // Configuration variables that store whether or not to replace the specimen with it's mean counterpart var config bool bReplaceCrawler, bReplaceStalker, bReplaceClot, bReplaceGorefast, bReplaceBloat, bReplaceSiren, bReplaceHusk, bReplaceScrake, bReplaceFleshpound; var config int bigZedMinHealth; // If zed's base Health >= this value, zed counts as Big var config int mediumZedMinHealth; var int maxPlayersInGame; var bool bSpawnRateEnforced; // Set to true after spawn rate was altered // 'Adrenaline junkie' zed-time extensions var int junkieDoneGoals; // How many times we collected enough head-shots to trigger zed-time extension var int junkieNextGoal; // How many head-shots we need for next zed-time extension var int junkieDoneHeadshots; // How many head-shot in a row was done from the start of last zed-time var array replCaps; var bool bFFWasIncreased; var int nextSirenScreamID; var int stuckCounter; // Max dead bodies among all players var int maxDeadBodies; var int deadBodyCounter; var ScrnBalance ScrnMut; var ScrnGameType ScrnGT; var NiceGameType NiceGT; var NicePack Mut; var NiceRules GameRules; var NiceStorageServer serverStorage; var bool bClientLinkEstablished; var bool interactionAdded; var bool bIsPreGame; var bool bIsTraderTime; var bool bWasZedTime; var array recordedHumanPawns; struct PlayerRecord{ var string steamID; var bool bHasSpawned; var int lastCashWave; //Last wave in which player either participated, or for which he received cash var int kills, assists, deaths; }; var array PlayerDatabase; // Zed hardcore level record struct ZedRecord{ var string ZedName; var class ZedType; var class MeanZedType; var bool bAlreadySpawned; var bool bMeanAlreadySpawned; var float HL; var float MeanHLBonus; var bool bNeedsReplacement; }; var int lastStandardZed; var array ZedDatabase; struct NicePickupReplacement{ var class vanillaClass; var class scrnClass; var class newClass; }; var array pickupReplaceArray; struct CounterDisplay{ var string cName; var Texture icon; var int value; var bool bShowZeroValue; var class ownerSkill; }; var array niceCounterSet; struct WeaponProgressDisplay{ var class weapClass; var float progress; var bool bShowCounter; var int counter; }; var array niceWeapProgressSet; // Map Description array var const array NiceUniversalDescriptions[4]; // Replication of config between player and server var int SrvFlags; var array playersList; var NicePathBuilder globalPathBuilder; replication{ reliable if(Role == ROLE_Authority) SrvFlags, bIsPreGame, junkieDoneHeadshots, junkieNextGoal; } static function NicePathBuilder GetPathBuilder(){ if(default.globalPathBuilder == none) default.globalPathBuilder = new() class'NicePathBuilder'; return default.globalPathBuilder; } static final function NiceStorageBase GetStorage(LevelInfo level){ local NicePlayerController localPlayer; if(default.serverStorage != none) return default.serverStorage; localPlayer = NicePlayerController(level.GetLocalPlayerController()); if(localPlayer != none) return localPlayer.storageClient; return none; } static final function NicePack Myself(LevelInfo Level){ local Mutator M; local NicePack NicePackMutator; if(default.Mut != none) return default.Mut; // server-side if(Level != none && Level.Game != none){ for(M = Level.Game.BaseMutator;M != none;M = M.NextMutator){ NicePackMutator = NicePack(M); if(NicePackMutator != none){ default.Mut = NicePackMutator; return NicePackMutator; } } } // client-side foreach Level.DynamicActors(class'NicePack', NicePackMutator){ default.Mut = NicePackMutator; return NicePackMutator; } return none; } function PreBeginPlay() { local ZombieVolume ZV; super.PreBeginPlay(); foreach AllActors(Class'ZombieVolume', ZV) ZV.MinDistanceToPlayer = minimalSpawnDistance; AddToPackageMap("NicePackA.ukx"); AddToPackageMap("NicePackSM.usx"); AddToPackageMap("NicePackSnd.uax"); AddToPackageMap("NicePackT.utx"); } simulated function PostBeginPlay() { local ScrnVotingHandlerMut VH; local MeanVoting VO; local NiceFFVoting FFVO; super.PostBeginPlay(); class'ScrnLightVestPickup'.default.cost = 50; class'ScrnHorzineVestPickup'.default.weight = 2; class'ScrnHorzineVestPickup'.default.cost = 750; class'NicePack'.default.Mut = self; // Abilities class'NiceAbilityManager'.default.events.static.AddAdapter(class'NiceSharpshooterAbilitiesAdapter', level); class'NiceAbilityManager'.default.events.static.AddAdapter(class'NiceEnforcerAbilitiesAdapter', level); SetTimer(0.25, true); if (Role < ROLE_Authority) return; // Create sync node serverStorage = new class'NiceStorageServer'; default.serverStorage = serverStorage; serverStorage.events.static.AddAdapter(class'NiceRemoteDataAdapter', Level); // Find game type and ScrN mutator ScrnGT = ScrnGameType(Level.Game); NiceGT = NiceGameType(Level.Game); if(ScrnGT == none){ Log("ERROR: Wrong GameType (requires at least ScrnGameType)", Class.Outer.Name); Destroy(); return; } // Skills menu ScrnGT.LoginMenuClass = string(class'NiceInvasionLoginMenu'); if(NiceGT != none) NiceGT.RegisterMutator(Self); ScrnMut = ScrnGT.ScrnBalanceMut; if(bReplacePickups) ScrnMut.bReplacePickups = false; // Replication of some variables SetReplicationData(); // New player controller class if(!ClassIsChildOf(ScrnGT.PlayerControllerClass, class'NicePlayerController')){ ScrnGT.PlayerControllerClass = class'NicePlayerController'; ScrnGT.PlayerControllerClassName = string(class'NicePlayerController'); } // Game rules GameRules = Spawn(class'NiceRules', self); // -- Lower starting HL ScrnMut.GameRules.HardcoreLevel -= 7; ScrnMut.GameRules.HardcoreLevelFloat -= 7; // -- Fill-in zed info // - Clot ZedDatabase[0].bNeedsReplacement = bReplaceClot; // - Crawler ZedDatabase[1].bNeedsReplacement = bReplaceCrawler; // - Stalker ZedDatabase[2].bNeedsReplacement = bReplaceStalker; // - Gorefast ZedDatabase[3].bNeedsReplacement = bReplaceGorefast; // - Bloat ZedDatabase[4].bNeedsReplacement = bReplaceBloat; // - Siren ZedDatabase[5].bNeedsReplacement = bReplaceSiren; // - Husk ZedDatabase[6].bNeedsReplacement = bReplaceHusk; // - Scrake ZedDatabase[7].bNeedsReplacement = bReplaceScrake; // - Fleshpound ZedDatabase[8].bNeedsReplacement = bReplaceFleshpound; // FIXME!!! lastStandardZed = 8; // Add voting for mean zeds VH = class'ScrnVotingHandlerMut'.static.GetVotingHandler(Level.Game); if(VH == none){ Level.Game.AddMutator(string(class'ScrnVotingHandlerMut'), false); VH = class'ScrnVotingHandlerMut'.static.GetVotingHandler(Level.Game); } if(VH != none){ VO = MeanVoting(VH.AddVotingOptions(class'MeanVoting')); if(VO != none) VO.Mut = self; FFVO = NiceFFVoting(VH.AddVotingOptions(class'NiceFFVoting')); if(FFVO != none) FFVO.Mut = self; } else log("Unable to spawn voting handler mutator", class.outer.name); } simulated function PostNetBeginPlay() { super.PostNetBeginPlay(); if(Role < ROLE_Authority) LoadReplicationData(); } function SetReplicationData(){ SrvFlags = 0; if(bInitialTrader) SrvFlags = SrvFlags | 0x00000001; if(bStillDuringInitTrader) SrvFlags = SrvFlags | 0x00000002; } simulated function LoadReplicationData(){ if(Role == ROLE_Authority) return; bInitialTrader = (SrvFlags & 0x00000001) > 0; bStillDuringInitTrader = (SrvFlags & 0x00000002) > 0; } simulated function Timer(){ local KFHumanPawn nextPawn; local int currentPlayersMax; local Controller P; local NicePlayerController nicePlayer; // Cull excessive pawns if(Role < Role_AUTHORITY){ recordedHumanPawns.Length = 0; foreach DynamicActors(class'KFHumanPawn', nextPawn) if(nextPawn != none && nextPawn.health > 0) recordedHumanPawns[recordedHumanPawns.Length] = nextPawn; return; } // Broadcast skills & record latest player controller list BroadcastSkills(); playersList.length = 0; for(P = Level.ControllerList; P != none; P = P.nextController){ nicePlayer = NicePlayerController(P); if(nicePlayer != none){ nicePlayer.wallHitsLeft = 10; //nicePlayer.FreeOldStuckBullets(); playersList[playersList.Length] = nicePlayer; if(nicePlayer.Pawn != none && nicePlayer.Pawn.health > 0 && !nicePlayer.PlayerReplicationInfo.bIsSpectator && !nicePlayer.PlayerReplicationInfo.bOnlySpectator) currentPlayersMax ++; } } maxPlayersInGame = Max(maxPlayersInGame, currentPlayersMax); } simulated function Tick(float Delta){ local int i; local NiceInteraction niceInt; local NicePlayerController localPlayer; super.Tick(Delta); if(ScrnGT != none && ScrnGT.WaveCountDown <= 5) bIsPreGame = false; if(ScrnMut != none && !bSpawnRateEnforced && ScrnMut.bTickExecuted){ bSpawnRateEnforced = true; ScrnMut.OriginalWaveSpawnPeriod = FMax(minSpawnRate, FMin(maxSpawnRate, ScrnMut.OriginalWaveSpawnPeriod)); } localPlayer = NicePlayerController(Level.GetLocalPlayerController()); // Check if the local PlayerController is available yet if(localPlayer == none) return; if( Role < Role_AUTHORITY && !bClientLinkEstablished && localPlayer.storageClient != none && localPlayer.remoteRI != none){ bClientLinkEstablished = true; localPlayer.storageClient.remoteRI = localPlayer.remoteRI; localPlayer.storageClient.events.static.CallLinkEstablished(); } if(localPlayer.bFlagDisplayCounters){ for(i = 0;i < niceCounterSet.Length;i ++){ if(niceCounterSet[i].ownerSkill == none) niceCounterSet[i].value = UpdateCounterValue(niceCounterSet[i].cName); else if(class'NiceVeterancyTypes'.static.hasSkill(localPlayer, niceCounterSet[i].ownerSkill)) niceCounterSet[i].value = niceCounterSet[i].ownerSkill.static. UpdateCounterValue(niceCounterSet[i].cName, localPlayer); else niceCounterSet[i].value = 0; } } // Reset tick counter for traces localPlayer.tracesThisTick = 0; // Manage resetting of effects' limits if(Level.TimeSeconds >= localPlayer.nextEffectsResetTime){ localPlayer.nextEffectsResetTime = Level.TimeSeconds + 0.1; localPlayer.currentEffectTimeWindow ++; if(localPlayer.currentEffectTimeWindow >= 10) localPlayer.currentEffectTimeWindow = 0; localPlayer.effectsSpawned[localPlayer.currentEffectTimeWindow] = 0; } // Add interaction if(interactionAdded) return; // Actually add the interaction niceInt = NiceInteraction(localPlayer.Player.InteractionMaster.AddInteraction(string(class'NiceInteraction'), localPlayer.Player)); niceInt.RegisterMutator(Self); interactionAdded = true; } simulated function bool CheckReplacement(Actor Other, out byte bSuperRelevant){ local int i; local NiceMonster niceMonster; local NiceZombieBoss boss; local Controller cIt; local int currNumPlayers; local NicePlayerController playerContr; local NiceRepInfoRemoteData remoteRI; local NiceReplicationInfo niceRI; local PlayerReplicationInfo pri; // Replace loot on levels if(Other.class == class'KFRandomItemSpawn' || Other.class == class'ScrnRandomItemSpawn'){ ReplaceWith(Other, string(class'NiceRandomItemSpawn')); return false; } else if(Other.class == class'KFAmmoPickup' || Other.class == class'ScrnAmmoPickup') { ReplaceWith(Other, string(class'NiceAmmoPickup')); return false; } else if(bReplacePickups && Pickup(Other) != none){ i = FindPickupReplacementIndex(Pickup(Other)); if (i != -1){ ReplaceWith(Other, String(pickupReplaceArray[i].NewClass)); return false; } return true; } // Add our replication info if(PlayerReplicationInfo(Other) != none && NicePlayerController(PlayerReplicationInfo(Other).Owner) != none){ pri = PlayerReplicationInfo(Other); niceRI = spawn(class'NiceReplicationInfo', pri.Owner); niceRI.Mut = self; remoteRI = spawn(class'NiceRepInfoRemoteData', pri.Owner); playerContr = NicePlayerController(PlayerReplicationInfo(Other).Owner); playerContr.niceRI = niceRI; playerContr.remoteRI = remoteRI; } niceMonster = NiceMonster(Other); if(niceMonster != none){ if (bUseProgresiveCash) { niceMonster.ScoringValue = 0; } } // Replace zeds with a healthier ones. // Code taken from a scary ghost's SpecimenHPConfig if(!bScaleZedHealth) return true; boss = NiceZombieBoss(Other); if(niceMonster != none){ for(cIt= Level.ControllerList; cIt != none; cIt= cIt.NextController) if(cIt.bIsPlayer && cIt.Pawn != none && cIt.Pawn.Health > 0) currNumPlayers++; if(boss == none) { niceMonster.Health *= hpScale(niceMonster.PlayerCountHealthScale) / niceMonster.NumPlayersHealthModifer(); niceMonster.HealthMax = niceMonster.Health; niceMonster.HeadHealth *= hpScale(niceMonster.PlayerNumHeadHealthScale) / niceMonster.NumPlayersHeadHealthModifer(); niceMonster.HeadHealthMax = niceMonster.HeadHealth; if(Level.Game.NumPlayers == 1){ niceMonster.MeleeDamage /= 0.75; niceMonster.ScreamDamage /= 0.75; niceMonster.SpinDamConst /= 0.75; niceMonster.SpinDamRand /= 0.75; } } } return true; } // returns -1, if not found function int FindPickupReplacementIndex(Pickup item) { local int i; for(i=0; i < pickupReplaceArray.length;i ++){ if(pickupReplaceArray[i].vanillaClass == item.class || pickupReplaceArray[i].scrnClass == item.class) return i; } return -1; } // Try to extend zed-time, junkie-style function JunkieZedTimeExtend(){ if((ScrnGT != none && !ScrnGT.bZEDTimeActive) || ScrnGT.CurrentZEDTimeDuration <= 0) return; junkieDoneHeadshots ++; if(junkieNextGoal <= junkieDoneHeadshots){ junkieDoneHeadshots = 0; junkieDoneGoals ++; junkieNextGoal ++; ScrnGT.DramaticEvent(1.0); } } simulated function AddCounter(string cName, Texture icon, optional bool bShowZeroValue, optional class owner){ local CounterDisplay newCounter; RemoveCounter(cName); newCounter.cName = cName; newCounter.icon = icon; newCounter.bShowZeroValue = bShowZeroValue; newCounter.ownerSkill = owner; niceCounterSet[niceCounterSet.Length] = newCounter; } simulated function RemoveCounter(string cName){ local int i; local array newCounterSet; for(i = 0;i < niceCounterSet.Length;i ++) if(niceCounterSet[i].cName != cName) newCounterSet[newCounterSet.Length] = niceCounterSet[i]; niceCounterSet = newCounterSet; } simulated function int GetVisibleCountersAmount(){ local int i; local int amount; for(i = 0;i < niceCounterSet.Length;i ++) if(niceCounterSet[i].value != 0 || niceCounterSet[i].bShowZeroValue) amount ++; return amount; } simulated function int UpdateCounterValue(string cName){ return 0; } simulated function AddWeapProgress(class weapClass, float progress, optional bool bShowCounter, optional int counter){ local WeaponProgressDisplay newProgress; newProgress.weapClass = weapClass; newProgress.progress = progress; newProgress.bShowCounter = bShowCounter; newProgress.counter = counter; niceWeapProgressSet[niceWeapProgressSet.Length] = newProgress; } simulated function ClearWeapProgress(){ niceWeapProgressSet.Length = 0; } // Returns cash per wave based on current difficulty // Returns cash per wave based on current difficulty function int GetWaveCash(int lastCashWave, int nextWave){ local int i; local int accumulatedDosh; for (i = lastCashWave; i < nextWave; i += 1) { accumulatedDosh += waveCash[i]; } if (lastCashWave + 1 < nextWave) { accumulatedDosh *= lateMultiplier; } return accumulatedDosh; } // Gives out appropriate (for the wave he entered) amount of dosh to the player function GiveProgressiveDosh(NicePlayerController nicePlayer){ local int nextWave; local PlayerRecord record; // Too early to give dosh if(!ScrnGT.IsInState('MatchInProgress')) return; // Real spectators shouldn't be affected if(nicePlayer == none) return; if(nicePlayer.PlayerReplicationInfo.bIsSpectator) return; if(nicePlayer.PlayerReplicationInfo.bOnlySpectator) return; record = FindPlayerRecord(nicePlayer.steamID64); nextWave = ScrnGT.WaveNum + 1; nicePlayer.PlayerReplicationInfo.Score += GetWaveCash(record.lastCashWave, nextWave); record.lastCashWave = nextWave; UpdatePlayerRecord(record); } simulated function Mutate(string MutateString, PlayerController kfPlayer) { local int i, readLenght; local NicePlayerController nicePlayer; local NiceServerData remoteData; // Tokens from 'MutateString' local array wordsArray; local String command, mod; local String white; local BitStreamWriter inputStream; local BitStreamReader outputStream; // Array with command modifiers. // Always contains at least 10 elements, that may be empty strings if there wasn't enough modifiers. // Done for safe access without the need to check for bounds. local array modArray; super.Mutate(MutateString, kfPlayer); // Helpful sequence white = chr(27)$chr(200)$chr(200)$chr(200); // Transform our command into array for convenience Split(MutateString, " ", wordsArray); // Exit if command is empty if(wordsArray.Length == 0) return; // Fancier access command = wordsArray[0]; if(wordsArray.Length > 1) mod = wordsArray[1]; else mod = ""; i = 0; while(i + 1 < wordsArray.Length || i < 10){ if(i + 1 < wordsArray.Length) modArray[i] = wordsArray[i+1]; else modArray[i] = ""; i ++; } nicePlayer = NicePlayerController(kfPlayer); if(command ~= "ECHO") kfPlayer.ClientMessage(Mid(MutateString, 5)); else if(command ~= "ZED" && bAlwaysAllowSkillChange) ScrnGT.DramaticEvent(1.0); else if(command ~= "SAVECFG" && nicePlayer != none) nicePlayer.ClientSaveConfig(); else if(command ~= "CONFIG" && nicePlayer != none){ if(nicePlayer.bFlagAltSwitchesModes) nicePlayer.ClientMessage(white$"Alt fire button will switch between single and burst modes for assault rifles"); else nicePlayer.ClientMessage(white$"Alt fire button will shoot either single or burst mode for assault rifles"); if(nicePlayer.bFlagShowHLMessages) nicePlayer.ClientMessage(white$"Messages about HL change will be displayed for you"); else nicePlayer.ClientMessage(white$"Messages about HL change will be hidden from you"); } else if(command ~= "HLMESSAGES" && nicePlayer != none){ if(mod ~= "ON") nicePlayer.ServerSetHLMessages(true); else if(mod ~= "OFF") nicePlayer.ServerSetHLMessages(false); } else if(command ~= "ALTSWITCH"){ if(mod ~= "ON") nicePlayer.ServerSetAltSwitchesModes(true); else if(mod ~= "OFF") nicePlayer.ServerSetAltSwitchesModes(false); } else if(command ~= "SETKEY" && nicePlayer != none){ if(Int(mod) > 0) nicePlayer.ClientSetKey(Int(mod)); } else if(command ~= "NICEWEAPMANAGE" && nicePlayer != none){ if(mod ~= "ON") nicePlayer.ClientSetNiceWeapManagement(true); else if(mod ~= "OFF") nicePlayer.ClientSetNiceWeapManagement(false); } else if(command ~= "DEBUG" && nicePlayer != none){ if(mod ~= "ON") nicePlayer.ServerSetDebug(true); else if(mod ~= "OFF") nicePlayer.ServerSetDebug(false); } else if(command ~= "LOGLINE" && nicePlayer != none) nicePlayer.ClientLog("UserLine:"$mod); else if(command ~= "CREATE"){ nicePlayer.ClientMessage("ATTEMPT"@string(serverStorage)); serverStorage.CreateData(modArray[0], NSP_HIGH); remoteData = NiceServerData(serverStorage.GetData(modArray[0])); remoteData.isAdminOnly = true; nicePlayer.ClientMessage("ATTEMPT2"@string(remoteData)); } else if(command ~= "CREATELOW"){ serverStorage.CreateData(modArray[0], NSP_LOW); } else if(command ~= "SET"){ remoteData = NiceServerData(serverStorage.GetData(modArray[0])); nicePlayer.ClientMessage("SETATTEMPT"@string(remoteData)); remoteData.SetInt(modArray[1], Int(modArray[2])); nicePlayer.ClientMessage("SETATTEMPT 2"@modArray[1]@modArray[2]); } else if(command ~= "PRINT"){ nicePlayer.ClientPrint(); } else if(command ~= "TEST"){ inputStream = new class'BitStreamWriter'; outputStream = new class'BitStreamReader'; inputStream.WriteInt(Len(mod), 5); inputStream.WriteClassName(mod); outputStream.Initialize(inputStream.GetData()); readLenght = outputStream.ReadInt(5); nicePlayer.ClientMessage("Input lenght:" @ string(Len(mod))); nicePlayer.ClientMessage("Compressed lenght:" @ string(inputStream.GetSizeInBytes()) ); nicePlayer.ClientMessage("Output:"@outputStream.ReadClassName(readLenght)); } } /* Good test for writer else if(command ~= "TEST"){ inputStream = new class'BitStreamWriter'; outputStream = new class'BitStreamReader'; //stream.PushByte(167, int(mod)); inputStream.WriteInt(3, 3); inputStream.WriteByte(49, 7); inputStream.WriteInt(1651779982, 25); inputStream.WriteInt(2, 2); bytes = inputStream.GetData(); bits = inputStream.GetSize(); nicePlayer.ClientMessage("SIZE:" @ string(bits)); for (i = 0; i < bytes.length; i += 1) { nicePlayer.ClientMessage("Content:" @ string(bytes[i])); } outputStream.Initialize(bytes); //nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(3))); //nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(7))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(8))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(4))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(4))); outputStream.Initialize(bytes); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(3))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(7))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(5))); outputStream.Initialize(bytes); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadInt(3))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadByte(7))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadInt(25))); nicePlayer.ClientMessage("OUT:" @ string(outputStream.ReadInt(2))); } */ // Event functions // Called at the start of the match function MatchBegan(){ } // Called when new wave begins function WaveStart(){ local Controller P; local NiceHumanPawn nicePawn; local NicePlayerController nicePlayer; bIsPreGame = false; bIsTraderTime = false; for(P = Level.ControllerList; P != none; P = P.nextController){ nicePlayer = NicePlayerController(P); if(nicePlayer != none){ // Give out armor nicePawn = NiceHumanPawn(nicePlayer.Pawn); if(nicePawn != none && nicePawn.Health > 0){ nicePawn.bGotFreeJacket = false; nicePawn.getFreeJacket(); nicePawn.bReactiveArmorUsed = false; } } } } // Called when trader time begins simulated function TraderStart(){ local Controller P; local NiceHumanPawn nicePawn; local NicePlayerController nicePlayer; bIsTraderTime = true; for(P = Level.ControllerList; P != none; P = P.nextController){ nicePlayer = NicePlayerController(P); if(nicePlayer != none){ nicePlayer.TryActivatePendingSkills(); nicePlayer.ClientSaveConfig(); nicePawn = NiceHumanPawn(nicePlayer.Pawn); if (bUseProgresiveCash) { GiveProgressiveDosh(nicePlayer); } } } } // Called when zed-time begins simulated function ZedTimeActivated(){ } // Called when zed-time deactivated simulated function ZedTimeDeactivated(){ local Controller P; local NicePlayerController Player; junkieNextGoal=1; junkieDoneGoals=0; junkieDoneHeadshots=0; for(P = Level.ControllerList; P != none; P = P.nextController){ Player = NicePlayerController(P); if(Player != none) Player.bJunkieExtFailed = false; } } // Returns player record, corresponding to the given steam id function PlayerRecord FindPlayerRecord(string steamID){ local int i; local PlayerRecord newRecord; for(i = 0;i < PlayerDatabase.Length;i ++) if(PlayerDatabase[i].steamID == steamID) return PlayerDatabase[i]; newRecord.steamID = steamID; newRecord.bHasSpawned = false; newRecord.lastCashWave = 0; newRecord.kills = 0; newRecord.assists = 0; newRecord.deaths = 0; PlayerDatabase[PlayerDatabase.Length] = newRecord; return newRecord; } // Updates existing PlayerRecord (with a same steam id) and adds a new one, if necessary (record with a same steam is not found) function UpdatePlayerRecord(PlayerRecord record){ local int i; for(i = 0;i < PlayerDatabase.Length;i ++) if(PlayerDatabase[i].steamID == record.steamID){ PlayerDatabase[i] = record; return; } PlayerDatabase[PlayerDatabase.Length] = record; } // Checks if it should be possible to change skills right now function bool CanChangeSkill(NicePlayerController player){ local PlayerRecord record; record = FindPlayerRecord(player.SteamID64); return (bIsTraderTime || (bIsPreGame && bInitialTrader) || bAlwaysAllowSkillChange || !record.bHasSpawned); } // Outputs info about given skill in console function DisplaySkill(class skill, int level, bool selected, PlayerController player){ local String skillColor; local String white; if(selected) skillColor = chr(27)$chr(1)$chr(200)$chr(1); else skillColor = chr(27)$chr(200)$chr(1)$chr(1); white = chr(27)$chr(200)$chr(200)$chr(200); player.ClientMessage(white$"Level"@String(level)$skillColor@"skill"$white$":"@skill.default.SkillName); // Just in case description is too long player.ClientMessage(" "); } function UpdateHealthLevels(){ local Controller P, S; local NiceHumanPawn updatePawn; for(P = Level.ControllerList;P != none;P = P.nextController){ updatePawn = NiceHumanPawn(P.Pawn); if(updatePawn == none) continue; updatePawn.HealthMax = (updatePawn.default.HealthMax + updatePawn.HealthBonus) * updatePawn.ScrnPerk.static.HealthMaxMult(KFPlayerReplicationInfo(P.PlayerReplicationInfo), updatePawn); for(S = Level.ControllerList;S != none;S = S.nextController) if(NicePlayerController(S) != none) NicePlayerController(S).ClientUpdatePawnMaxHealth(updatePawn, updatePawn.HealthMax); } } function BroadcastSkills(){ local int i, j; local bool bSameSkillFound; local Controller P; local NicePlayerController nicePlayer; local array< class > playerSkills; // Skills to broadcast local array teamNumbers; local array< class > skillsToSend; for(P = Level.ControllerList;P != none;P = P.nextController){ nicePlayer = NicePlayerController(P); if(nicePlayer != none){ playerSkills = nicePlayer.GetActiveBroadcastSkills(); // Process player's skills for(i = 0;i < playerSkills.Length;i ++){ bSameSkillFound = false; // Try to find if someone already shares the same skill in the same team for(j = 0;j < skillsToSend.Length && !bSameSkillFound;j ++) if(playerSkills[i] == skillsToSend[j] && teamNumbers[j] == nicePlayer.PlayerReplicationInfo.Team.TeamIndex) bSameSkillFound = true; // If not - add it if(!bSameSkillFound){ teamNumbers[teamNumbers.Length] = nicePlayer.PlayerReplicationInfo.Team.TeamIndex; skillsToSend[skillsToSend.Length] = playerSkills[i]; } } } } for(P = Level.ControllerList;P != none;P = P.nextController){ nicePlayer = NicePlayerController(P); if(nicePlayer != none){ for(i = 0;i < skillsToSend.Length;i ++) if(teamNumbers[i] == nicePlayer.PlayerReplicationInfo.Team.TeamIndex) nicePlayer.ClientReceiveSkill(skillsToSend[i]); nicePlayer.ClientBroadcastEnded(); } } } // Function for broadcasting messages to players function BroadcastToAll(string message){ local Controller P; local PlayerController Player; for(P = Level.ControllerList; P != none; P = P.nextController){ Player = PlayerController(P); if(Player != none) Player.ClientMessage(message); } } // Function for finding number, corresponding to zed's name function int ZedNumber(String ZedName){ local int i; for(i = 0;i < ZedDatabase.Length;i ++) if(ZedName ~= ZedDatabase[i].ZedName) return i; return -1; } // Function for correct hp scaling function float hpScale(float hpScale) { return 1.0 + 5.0 * hpScale; } static function FillPlayInfo(PlayInfo PlayInfo){ Super.FillPlayInfo(PlayInfo); PlayInfo.AddSetting("NicePack", "bScaleZedHealth", "Scale zeds' health?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "bReplacePickups", "Replace pickups?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "bInitialTrader", "Use init trader?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "bStillDuringInitTrader", "Be still during init trader?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "initialTraderTime", "Time for init trader?", 0, 0, "text", "3;1:999"); PlayInfo.AddSetting("NicePack", "bUseProgresiveCash", "Use progressive dosh?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "bConvertExp", "Convert old exp?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "bAlwaysAllowSkillChange", "Skill change at anytime?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "minimalSpawnDistance", "Min spawn distance", 0, 0, "text", "5;0:99999"); PlayInfo.AddSetting("NicePack", "minSpawnRate", "Min spawn rate", 0, 0, "text", "6;0.0:10.0"); PlayInfo.AddSetting("NicePack", "maxSpawnRate", "Max spawn rate", 0, 0, "text", "6;0.0:10.0"); PlayInfo.AddSetting("NicePack", "bOneFFIncOnly", "Only 1 FF increase?", 0, 0, "check"); PlayInfo.AddSetting("NicePack", "bNoLateFFIncrease", "FF increase wave 1 only?", 0, 0, "check"); } static function string GetDescriptionText(string SettingName){ switch (SettingName){ case "bScaleZedHealth": return "Should we scale health off all zeds to 6-player level?"; case "bReplacePickups": return "Should we replace all pickups with their Nice versions when available?"; case "bInitialTrader": return "Use initial trader system?"; case "bStillDuringInitTrader": return "Force players to stand still during initial trader?"; case "initialTraderTime": return "How much time should be allowed for initial trade?"; case "bUseProgresiveCash": return "Use progressive dosh system?"; case "bConvertExp": return "Should we convert old exp into a new one?"; case "bAlwaysAllowSkillChange": return "Allows changing skills at any time."; case "minimalSpawnDistance": return "Minimal distance between ZedVolume and players that should allow for zeds to spawn."; case "minSpawnRate": return "Minimal allowed spawn rate."; case "maxSpawnRate": return "Maximal allowed spawn rate."; case "bOneFFIncOnly": return "Option that only allows one FF increase per game."; case "bNoLateFFIncrease": return "Disables FF increase through voting after 1st wave."; } return Super.GetDescriptionText(SettingName); } defaultproperties { ZedDatabase(0)=(ZedName="Clot",ZedType=class'NiceZombieClot',MeanZedType=class'MeanZombieClot',HL=0.0,MeanHLBonus=0.5) ZedDatabase(1)=(ZedName="Crawler",ZedType=class'NiceZombieCrawler',MeanZedType=class'MeanZombieCrawler',HL=0.5,MeanHLBonus=1.5) ZedDatabase(2)=(ZedName="Stalker",ZedType=class'NiceZombieStalker',MeanZedType=class'MeanZombieStalker',HL=0.5,MeanHLBonus=0.5) ZedDatabase(3)=(ZedName="Gorefast",ZedType=class'NiceZombieGorefast',MeanZedType=class'MeanZombieGorefast',HL=0.0,MeanHLBonus=0.5) ZedDatabase(4)=(ZedName="Bloat",ZedType=class'NiceZombieBloat',MeanZedType=class'MeanZombieBloat',HL=0.0,MeanHLBonus=0.5) ZedDatabase(5)=(ZedName="Siren",ZedType=class'NiceZombieSiren',MeanZedType=class'MeanZombieSiren',HL=1.0,MeanHLBonus=1.0) ZedDatabase(6)=(ZedName="Husk",ZedType=class'NiceZombieHusk',MeanZedType=class'MeanZombieHusk',HL=1.0,MeanHLBonus=1.5) ZedDatabase(7)=(ZedName="Scrake",ZedType=class'NiceZombieScrake',MeanZedType=class'MeanZombieScrake',HL=1.5,MeanHLBonus=1.5) ZedDatabase(8)=(ZedName="Fleshpound",ZedType=class'NiceZombieFleshPound',MeanZedType=class'MeanZombieFleshPound',HL=2.5,MeanHLBonus=1.5) ZedDatabase(9)=(ZedName="Shiver",ZedType=class'NiceZombieShiver',HL=1.0) ZedDatabase(10)=(ZedName="Jason",ZedType=class'NiceZombieJason',HL=1.5) ZedDatabase(11)=(ZedName="Tesla Husk",ZedType=class'NiceZombieTeslaHusk',HL=1.5) ZedDatabase(12)=(ZedName="Brute",ZedType=class'NiceZombieBrute',HL=2.0) ZedDatabase(13)=(ZedName="Ghost",ZedType=class'NiceZombieGhost',HL=0.5) ZedDatabase(14)=(ZedName="Sick",ZedType=class'NiceZombieSick',HL=1.0) bScaleZedHealth=True bReplacePickups=True bInitialTrader=True initialTraderTime=10 bUseProgresiveCash=True waveCash(0)=1000 waveCash(1)=900 waveCash(2)=800 waveCash(3)=650 waveCash(4)=600 waveCash(5)=450 waveCash(6)=350 waveCash(7)=250 lateMultiplier=0.5 bConvertExp=True vetFieldMedicExpCost=2.000000 vetFieldMedicDmgExpCost=0.025000 vetSharpHeadshotExpCost=10.000000 vetSupportDamageExpCost=0.050000 vetCommandoDamageExpCost=0.050000 vetDemoDamageExpCost=0.050000 vetZerkDamageExpCost=0.050000 vetHeavyMGDamageExpCost=0.050000 vetGunslingerKillExpCost=20.000000 bigZedMinHealth=1000 mediumZedMinHealth=500 minSpawnRate=0.700000 maxSpawnRate=1.500000 minimalSpawnDistance=600 bNoLateFFIncrease=True junkieNextGoal=1 bIsPreGame=True pickupReplaceArray(0)=(vanillaClass=Class'KFMod.MAC10Pickup',scrnClass=Class'ScrnMAC10Pickup',NewClass=class'NiceMAC10Pickup') pickupReplaceArray(1)=(vanillaClass=Class'KFMod.WinchesterPickup',scrnClass=Class'ScrnWinchesterPickup',NewClass=class'NiceWinchesterPickup') pickupReplaceArray(2)=(vanillaClass=Class'KFMod.CrossbowPickup',scrnClass=Class'ScrnCrossbowPickup',NewClass=class'NiceCrossbowPickup') pickupReplaceArray(3)=(vanillaClass=Class'KFMod.SPSniperPickup',scrnClass=Class'ScrnSPSniperPickup',NewClass=class'NiceMaulerPickup') pickupReplaceArray(4)=(vanillaClass=Class'KFMod.M14EBRPickup',scrnClass=Class'ScrnM14EBRPickup',NewClass=class'NiceM14EBRPickup') pickupReplaceArray(5)=(vanillaClass=Class'KFMod.M99Pickup',scrnClass=Class'ScrnM99Pickup',NewClass=class'NiceM99Pickup') pickupReplaceArray(6)=(vanillaClass=Class'KFMod.ShotgunPickup',scrnClass=Class'ScrnShotgunPickup',NewClass=class'NiceShotgunPickup') pickupReplaceArray(7)=(vanillaClass=Class'KFMod.BoomStickPickup',scrnClass=Class'ScrnBoomStickPickup',NewClass=class'NiceBoomStickPickup') pickupReplaceArray(8)=(vanillaClass=Class'KFMod.NailGunPickup',scrnClass=Class'ScrnNailGunPickup',NewClass=class'NiceNailGunPickup') pickupReplaceArray(9)=(vanillaClass=Class'KFMod.KSGPickup',scrnClass=Class'ScrnKSGPickup',NewClass=class'NiceKSGPickup') pickupReplaceArray(10)=(vanillaClass=Class'KFMod.BenelliPickup',scrnClass=Class'ScrnBenelliPickup',NewClass=class'NiceBenelliPickup') pickupReplaceArray(11)=(vanillaClass=Class'KFMod.AA12Pickup',scrnClass=Class'ScrnAA12Pickup',NewClass=class'NiceAA12Pickup') pickupReplaceArray(12)=(vanillaClass=Class'KFMod.MachetePickup',scrnClass=Class'ScrnMachetePickup',NewClass=class'NiceMachetePickup') NiceUniversalDescriptions(0)="Survive on %m in ScrN Balance mode" NiceUniversalDescriptions(1)="Survive on %m in ScrN Balance mode with Hardcore Level 5+" NiceUniversalDescriptions(2)="Survive on %m in ScrN Balance mode with Hardcore Level 10+" NiceUniversalDescriptions(3)="Survive on %m in ScrN Balance mode with Hardcore Level 15+" bAddToServerPackages=True GroupName="KFNicePack" FriendlyName="Package for nice/mean servers" Description="Does stuff." bAlwaysRelevant=True RemoteRole=ROLE_SimulatedProxy }