NicePack/sources/NicePack.uc
2022-07-19 19:26:56 +04:00

979 lines
39 KiB
Ucode

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<int> 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;
// '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<String> 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 interactionAdded;
var bool bIsPreGame;
var bool bIsTraderTime;
var bool bWasZedTime;
var array<KFHumanPawn> 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<PlayerRecord> PlayerDatabase;
// Zed hardcore level record
struct ZedRecord{
var string ZedName;
var class<NiceMonster> ZedType;
var class<NiceMonster> MeanZedType;
var bool bAlreadySpawned;
var bool bMeanAlreadySpawned;
var float HL;
var float MeanHLBonus;
var bool bNeedsReplacement;
};
var int lastStandardZed;
var array<ZedRecord> ZedDatabase;
struct NicePickupReplacement{
var class<Pickup> vanillaClass;
var class<Pickup> scrnClass;
var class<Pickup> newClass;
};
var array<NicePickupReplacement> pickupReplaceArray;
struct CounterDisplay{
var string cName;
var Texture icon;
var int value;
var bool bShowZeroValue;
var class<NiceSkill> ownerSkill;
};
var array<CounterDisplay> niceCounterSet;
// Replication of config between player and server
var int SrvFlags;
var array<NicePlayerController> 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 (NiceGT == none)
{
Log("ERROR: Wrong GameType (requires NiceGameType)", class.Outer.Name);
Destroy();
return;
}
// FIXME poosh forces this variable in his mutator...
NiceGT.LoginMenuClass = string(class'NiceInvasionLoginMenu');
NiceGT.RegisterMutator(self);
ScrnMut = NiceGT.ScrnBalanceMut;
if(bReplacePickups)
ScrnMut.bReplacePickups = false;
// Replication of some variables
SetReplicationData();
// 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();
}
simulated function LoadReplicationData()
{
bInitialTrader = (SrvFlags & 0x00000001) > 0;
bStillDuringInitTrader = (SrvFlags & 0x00000002) > 0;
}
function SetReplicationData()
{
SrvFlags = 0;
if (bInitialTrader)
SrvFlags = SrvFlags | 0x00000001;
if (bStillDuringInitTrader)
SrvFlags = SrvFlags | 0x00000002;
}
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);
}
// initial tick, does some job and shuts down
auto state loadInteractionnSpawnRate
{
// state tick, overrides global
simulated function Tick(float Delta)
{
local NiceInteraction niceInt;
local NicePlayerController localPlayer;
if (level.netMode == NM_DedicatedServer)
{
// set spawn rate!
if (ScrnMut != none)
ScrnMut.OriginalWaveSpawnPeriod = FMax(minSpawnRate, FMin(maxSpawnRate, ScrnMut.OriginalWaveSpawnPeriod));
// do not execute below code on dedicated servers!
GoToState('');
DisableServerGlobalTick();
return;
}
localPlayer = NicePlayerController(Level.GetLocalPlayerController());
if (localPlayer == none)
return;
// spawn some magic
if (localPlayer.storageClient != none && localPlayer.remoteRI != none)
{
localPlayer.storageClient.remoteRI = localPlayer.remoteRI;
localPlayer.storageClient.events.static.CallLinkEstablished();
}
// Actually add the interaction
niceInt = NiceInteraction(localPlayer.Player.InteractionMaster.AddInteraction(string(class'NiceInteraction'), localPlayer.Player));
niceInt.RegisterMutator(Self);
// break this state and go to global
GoToState('');
}
}
// disable tick for servers!
final private function DisableServerGlobalTick()
{
Disable('Tick');
}
// global tick
simulated function Tick(float Delta)
{
local int i;
local NicePlayerController localPlayer;
localPlayer = NicePlayerController(Level.GetLocalPlayerController());
// Check if the local PlayerController is available yet
if (localPlayer == none)
return;
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;
}
}
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<NiceSkill> 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<CounterDisplay> 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;
}
// 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<String> 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<String> 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<NiceSkill> 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<NiceSkill> > playerSkills;
// Skills to broadcast
local array<int> teamNumbers;
local array< class<NiceSkill> > 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
{
GroupName="KFNicePack"
FriendlyName="Package for nice/mean servers"
Description="Does stuff."
bAlwaysRelevant=True
RemoteRole=ROLE_SimulatedProxy
bAddToServerPackages=True
// used in scrn voting and HL calculation
// TODO remove HL!
ZedDatabase(00)=(ZedName="Clot",ZedType=class'NiceZombieClot',MeanZedType=class'MeanZombieClot',HL=0.0,MeanHLBonus=0.5)
ZedDatabase(01)=(ZedName="Crawler",ZedType=class'NiceZombieCrawler',MeanZedType=class'MeanZombieCrawler',HL=0.5,MeanHLBonus=1.5)
ZedDatabase(02)=(ZedName="Stalker",ZedType=class'NiceZombieStalker',MeanZedType=class'MeanZombieStalker',HL=0.5,MeanHLBonus=0.5)
ZedDatabase(03)=(ZedName="Gorefast",ZedType=class'NiceZombieGorefast',MeanZedType=class'MeanZombieGorefast',HL=0.0,MeanHLBonus=0.5)
ZedDatabase(04)=(ZedName="Bloat",ZedType=class'NiceZombieBloat',MeanZedType=class'MeanZombieBloat',HL=0.0,MeanHLBonus=0.5)
ZedDatabase(05)=(ZedName="Siren",ZedType=class'NiceZombieSiren',MeanZedType=class'MeanZombieSiren',HL=1.0,MeanHLBonus=1.0)
ZedDatabase(06)=(ZedName="Husk",ZedType=class'NiceZombieHusk',MeanZedType=class'MeanZombieHusk',HL=1.0,MeanHLBonus=1.5)
ZedDatabase(07)=(ZedName="Scrake",ZedType=class'NiceZombieScrake',MeanZedType=class'MeanZombieScrake',HL=1.5,MeanHLBonus=1.5)
ZedDatabase(08)=(ZedName="Fleshpound",ZedType=class'NiceZombieFleshPound',MeanZedType=class'MeanZombieFleshPound',HL=2.5,MeanHLBonus=1.5)
ZedDatabase(09)=(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
// replace pickups that map spawn's itself
pickupReplaceArray(00)=(vanillaClass=Class'KFMod.MAC10Pickup',scrnClass=Class'ScrnMAC10Pickup',NewClass=class'NiceMAC10Pickup')
pickupReplaceArray(01)=(vanillaClass=Class'KFMod.WinchesterPickup',scrnClass=Class'ScrnWinchesterPickup',NewClass=class'NiceWinchesterPickup')
pickupReplaceArray(02)=(vanillaClass=Class'KFMod.CrossbowPickup',scrnClass=Class'ScrnCrossbowPickup',NewClass=class'NiceCrossbowPickup')
pickupReplaceArray(03)=(vanillaClass=Class'KFMod.SPSniperPickup',scrnClass=Class'ScrnSPSniperPickup',NewClass=class'NiceMaulerPickup')
pickupReplaceArray(04)=(vanillaClass=Class'KFMod.M14EBRPickup',scrnClass=Class'ScrnM14EBRPickup',NewClass=class'NiceM14EBRPickup')
pickupReplaceArray(05)=(vanillaClass=Class'KFMod.M99Pickup',scrnClass=Class'ScrnM99Pickup',NewClass=class'NiceM99Pickup')
pickupReplaceArray(06)=(vanillaClass=Class'KFMod.ShotgunPickup',scrnClass=Class'ScrnShotgunPickup',NewClass=class'NiceShotgunPickup')
pickupReplaceArray(07)=(vanillaClass=Class'KFMod.BoomStickPickup',scrnClass=Class'ScrnBoomStickPickup',NewClass=class'NiceBoomStickPickup')
pickupReplaceArray(08)=(vanillaClass=Class'KFMod.NailGunPickup',scrnClass=Class'ScrnNailGunPickup',NewClass=class'NiceNailGunPickup')
pickupReplaceArray(09)=(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')
}