First commit

This commit is contained in:
Anton Tarasenko 2020-02-16 19:53:59 +07:00
commit 5b48414900
263 changed files with 24830 additions and 0 deletions

0
README.md Normal file
View File

View File

@ -0,0 +1,126 @@
//==============================================================================
// NicePack / NiceClientData
//==============================================================================
// Adds data interface relevant only to client,
// as well as client implementation of more general functions.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceClientData extends NiceData
config(NicePack);
var protected NiceStorageClient ownerStorage;
// Server has yet unsent changes to this data
// (according to latest information from server)
var protected bool _isUpToDate;
// We can currently send server changes in this data
var protected bool _hasWriteRights;
static function NiceData NewData(string newID){
local NiceData newData;
newData = new class'NiceClientData';
newData.ID = newID;
return newData;
}
// #private
function SetOwnerStorage( NiceRemoteHack.DataRef dataRef,
NiceStorageClient newOwner){
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef))
ownerStorage = newOwner;
}
function bool IsUpToDate(){
return _isUpToDate;
}
// #private
function SetUpToDate(NiceRemoteHack.DataRef dataRef, bool newStatus){
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef))
_isUpToDate = newStatus;
}
function bool HasWriteRights(){
return _hasWriteRights;
}
// #private
function SetWriteRights(NiceRemoteHack.DataRef dataRef, bool newRights){
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef))
_hasWriteRights = newRights;
}
//==============================================================================
// > Setter / getters for variables that perform necessary synchronization
function SetByte(string variableName, byte variableValue){
if(!HasWriteRights()) return;
if(ownerStorage == none) return;
if(ownerStorage.remoteRI == none) return;
_SetByte(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallByteVariableUpdated(ID, variableName, variableValue);
ownerStorage.remoteRI.ServerSendByte(V(ID, variableName), variableValue);
}
function SetInt(string variableName, int variableValue){
if(!HasWriteRights()) return;
if(ownerStorage == none) return;
if(ownerStorage.remoteRI == none) return;
_SetInt(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallIntVariableUpdated(ID, variableName, variableValue);
ownerStorage.remoteRI.ServerSendInt(V(ID, variableName), variableValue);
}
function SetBool(string variableName, bool variableValue){
if(!HasWriteRights()) return;
if(ownerStorage == none) return;
if(ownerStorage.remoteRI == none) return;
_SetBool(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallBoolVariableUpdated(ID, variableName, variableValue);
ownerStorage.remoteRI.ServerSendBool(V(ID, variableName), variableValue);
}
function SetFloat(string variableName, float variableValue){
if(!HasWriteRights()) return;
if(ownerStorage == none) return;
if(ownerStorage.remoteRI == none) return;
_SetFloat(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallFloatVariableUpdated(ID, variableName, variableValue);
ownerStorage.remoteRI.ServerSendFloat(V(ID, variableName), variableValue);
}
function SetString(string variableName, string variableValue){
if(!HasWriteRights()) return;
if(ownerStorage == none) return;
if(ownerStorage.remoteRI == none) return;
_SetString(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallStringVariableUpdated(ID, variableName, variableValue);
ownerStorage.remoteRI.ServerSendString(V(ID, variableName), variableValue);
}
function SetClass(string variableName, class<Actor> variableValue){
if(!HasWriteRights()) return;
if(ownerStorage == none) return;
if(ownerStorage.remoteRI == none) return;
_SetClass(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallClassVariableUpdated(ID, variableName, variableValue);
ownerStorage.remoteRI.ServerSendClass(V(ID, variableName), variableValue);
}
defaultproperties
{
}

243
sources/Data/NiceData.uc Normal file
View File

@ -0,0 +1,243 @@
//==============================================================================
// NicePack / NiceData
//==============================================================================
// Base class for remote data, defines basic interface,
// used by both server and client storages.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceData extends NiceRemoteHack
abstract
config(NicePack);
var const class<NiceRemoteDataEvents> events;
enum EValueType{
VTYPE_BOOL,
VTYPE_BYTE,
VTYPE_INT,
VTYPE_FLOAT,
VTYPE_STRING,
VTYPE_CLASS,
VTYPE_NULL // Variable doesn't exist (in this storage)
};
struct Variable{
var protected string myName;
// Value of what type is currently stored in this struct
var protected EValueType currentType;
// Containers for various value types
var protected byte storedByte;
var protected int storedInt;
var protected bool storedBool;
var protected float storedFloat;
var protected string storedString;
var protected class<Actor> storedClass;
};
enum EDataPriority{ // Data change messages from server to client are...
// ...sent immediately;
NSP_REALTIME,
// ...sent with time intervals between them;
NSP_HIGH,
// ...sent with time intervals between them,
// but only if high-priority queue is empty.
NSP_LOW
// Data change messages from clients are always sent immediately.
};
var protected string ID;
var protected array<Variable> variables;
static function NiceData NewData(string newID){
local NiceData newData;
newData = new class'NiceData';
newData.ID = newID;
return newData;
}
function string GetID(){
return ID;
}
function bool IsEmpty(){
return variables.length <= 0;
}
function EValueType GetVariableType(string variableName){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return VTYPE_NULL;
return variables[index].currentType;
}
function array<string> GetVariableNames(){
local int i;
local array<string> mapResult;
for(i = 0;i < variables.length;i ++)
mapResult[i] = variables[i].myName;
return mapResult;
}
protected function int GetVariableIndex(string variableName){
local int i;
for(i = 0;i < variables.length;i ++)
if(variables[i].myName ~= variableName)
return i;
return -1;
}
//==============================================================================
// > Setter / getters for variables that perform necessary synchronization.
function SetByte(string variableName, byte variableValue);
function byte GetByte(string variableName, optional byte defaultValue){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return defaultValue;
if(variables[index].currentType != EValueType.VTYPE_BYTE)
return defaultValue;
return variables[index].storedByte;
}
function SetInt(string variableName, int variableValue);
function int GetInt(string variableName, optional int defaultValue){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return defaultValue;
if(variables[index].currentType != EValueType.VTYPE_INT)
return defaultValue;
return variables[index].storedInt;
}
function SetBool(string variableName, bool variableValue);
function bool GetBool(string variableName, optional bool defaultValue){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return defaultValue;
if(variables[index].currentType != EValueType.VTYPE_BOOL)
return defaultValue;
return variables[index].storedBool;
}
function SetFloat(string variableName, float variableValue);
function float GetFloat(string variableName, optional float defaultValue){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return defaultValue;
if(variables[index].currentType != EValueType.VTYPE_FLOAT)
return defaultValue;
return variables[index].storedFloat;
}
function SetString(string variableName, string variableValue);
function string GetString(string variableName, optional string defaultValue){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return defaultValue;
if(variables[index].currentType != EValueType.VTYPE_STRING)
return defaultValue;
return variables[index].storedString;
}
function SetClass(string variableName, class<Actor> variableValue);
function class<Actor> GetClass( string variableName,
optional class<Actor> defaultValue){
local int index;
index = GetVariableIndex(variableName);
if(index < 0)
return defaultValue;
if(variables[index].currentType != EValueType.VTYPE_CLASS)
return defaultValue;
return variables[index].storedClass;
}
//==============================================================================
// > Setter that records variables locally, without any synchronization work.
// #private
function _SetByte(DataRef dataRef, byte variableValue){
local int index;
local Variable newValue;
newValue.myName = dataRef.variable;
newValue.storedByte = variableValue;
newValue.currentType = VTYPE_BYTE;
index = GetVariableIndex(dataRef.variable);
if(index < 0)
index = variables.length;
variables[index] = newValue;
}
function _SetInt(DataRef dataRef, int variableValue){
local int index;
local Variable newValue;
newValue.myName = dataRef.variable;
newValue.storedInt = variableValue;
newValue.currentType = VTYPE_INT;
index = GetVariableIndex(dataRef.variable);
if(index < 0)
index = variables.length;
variables[index] = newValue;
}
function _SetBool(DataRef dataRef, bool variableValue){
local int index;
local Variable newValue;
newValue.myName = dataRef.variable;
newValue.storedBool = variableValue;
newValue.currentType = VTYPE_BOOL;
index = GetVariableIndex(dataRef.variable);
if(index < 0)
index = variables.length;
variables[index] = newValue;
}
function _SetFloat(DataRef dataRef, float variableValue){
local int index;
local Variable newValue;
newValue.myName = dataRef.variable;
newValue.storedFloat = variableValue;
newValue.currentType = VTYPE_FLOAT;
index = GetVariableIndex(dataRef.variable);
if(index < 0)
index = variables.length;
variables[index] = newValue;
}
function _SetString(DataRef dataRef, string variableValue){
local int index;
local Variable newValue;
newValue.myName = dataRef.variable;
newValue.storedString = variableValue;
newValue.currentType = VTYPE_STRING;
index = GetVariableIndex(dataRef.variable);
if(index < 0)
index = variables.length;
variables[index] = newValue;
}
function _SetClass(DataRef dataRef, class<Actor> variableValue){
local int index;
local Variable newValue;
newValue.myName = dataRef.variable;
newValue.storedClass = variableValue;
newValue.currentType = VTYPE_CLASS;
index = GetVariableIndex(dataRef.variable);
if(index < 0)
index = variables.length;
variables[index] = newValue;
}
defaultproperties
{
events=class'NiceRemoteDataEvents'
}

View File

@ -0,0 +1,16 @@
//==============================================================================
// NicePack / NiceDataQueue
//==============================================================================
// Implements a queue of updates for data stored on a server.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceDataQueue extends Object
config(NicePack);
defaultproperties
{
}

View File

@ -0,0 +1,79 @@
//==============================================================================
// NicePack / NiceRemoteDataAdapter
//==============================================================================
// Temporary stand-in for future functionality.
// Use this class to catch events from storages.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceRemoteDataAdapter extends Object
dependson(NiceStorageBase);
var LevelInfo level;
static function DataCreated(string dataID);
// Called on clients the moment client storage connects to the server one.
static function LinkEstablished();
// Called on client after server responds to his request
// to check if certain data exists.
static function DataExistResponse(string dataID, bool doesExist);
// Called on client after server responds to his connection request.
static function ConnectionRequestResponse
( string dataID,
NiceStorageBase.ECreateDataResponse response
);
// Fired-off when writing rights to a certain data were granted.
// Always called on server.
// Only called on client that gained writing rights.
static function WriteAccessGranted( string dataID,
NicePlayerController newOwner);
// Fired-off when server refused to grant writing rights to data.
// Always called on server.
// Only called on client that tried to gain writing rights.
static function WriteAccessRevoked( string dataID,
NicePlayerController newOwner);
// Fired-off when writing rights to a certain data were revoked.
// Always called on server.
// Only called on client that lost writing rights.
static function WriteAccessRefused( string dataID,
NicePlayerController newOwner);
// Fired off on client when server finished sending him all the info about
// particular data set.
static function DataUpToDate(string dataID);
// Fire off on server and listening clients when
// a particular variable was updated.
static function VariableUpdated( string dataID,
string varName);
static function BoolVariableUpdated(string dataID,
string varName,
bool newValue);
static function ByteVariableUpdated(string dataID,
string varName,
byte newValue);
static function IntVariableUpdated( string dataID,
string varName,
int newValue);
static function FloatVariableUpdated( string dataID,
string varName,
float newValue);
static function StringVariableUpdated( string dataID,
string varName,
string newValue);
static function ClassVariableUpdated( string dataID,
string varName,
class<Actor> newValue);
defaultproperties
{
}

View File

@ -0,0 +1,149 @@
//==============================================================================
// NicePack / NiceRemoteDataEvents
//==============================================================================
// Temporary stand-in for future functionality.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceRemoteDataEvents extends Object
dependson(NiceStorageBase);
var array< class<NiceRemoteDataAdapter> > adapters;
// If adapter was already added also returns 'false'.
static function bool AddAdapter(class<NiceRemoteDataAdapter> newAdapter,
optional LevelInfo level){
local int i;
if(newAdapter == none) return false;
for(i = 0;i < default.adapters.length;i ++)
if(default.adapters[i] == newAdapter)
return false;
newAdapter.default.level = level;
default.adapters[default.adapters.length] = newAdapter;
return true;
}
// If adapter wasn't even present also returns 'false'.
static function bool RemoveAdapter(class<NiceRemoteDataAdapter> adapter){
local int i;
if(adapter == none) return false;
for(i = 0;i < default.adapters.length;i ++){
if(default.adapters[i] == adapter){
default.adapters.Remove(i, 1);
return true;
}
}
return false;
}
static function CallLinkEstablished(){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.LinkEstablished();
}
static function CallDataCreated(string dataID){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.DataCreated(dataID);
}
static function CallDataExistResponse(string dataID, bool doesExist){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.DataExistResponse(dataID, doesExist);
}
static function CallConnectionRequestResponse
( string dataID,
NiceStorageBase.ECreateDataResponse response
){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.ConnectionRequestResponse(dataID, response);
}
static function CallVariableUpdated(string dataID, string variableName){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.VariableUpdated(dataID, variableName);
}
static function CallBoolVariableUpdated(string dataID, string variableName,
bool newValue){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.BoolVariableUpdated( dataID, variableName,
newValue);
}
static function CallByteVariableUpdated(string dataID, string variableName,
byte newValue){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.ByteVariableUpdated( dataID, variableName,
newValue);
}
static function CallIntVariableUpdated( string dataID, string variableName,
int newValue){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.IntVariableUpdated( dataID, variableName,
newValue);
}
static function CallFloatVariableUpdated( string dataID, string variableName,
float newValue){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.FloatVariableUpdated(dataID, variableName,
newValue);
}
static function CallStringVariableUpdated( string dataID, string variableName,
string newValue){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.StringVariableUpdated( dataID,
variableName,
newValue);
}
static function CallClassVariableUpdated( string dataID, string variableName,
class<Actor> newValue){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.ClassVariableUpdated(dataID, variableName,
newValue);
}
static function CallDataUpToDate(string dataID){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.DataUpToDate(dataID);
}
static function CallWriteAccessGranted( string dataID,
NicePlayerController newOwner){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.WriteAccessGranted(dataID, newOwner);
}
static function CallWritingAccessRevoked( string dataID,
NicePlayerController newOwner){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.WriteAccessRevoked(dataID, newOwner);
}
static function CallWriteAccessRefused( string dataID,
NicePlayerController newOwner){
local int i;
for(i = 0;i < default.adapters.length;i ++)
default.adapters[i].static.WriteAccessRefused(dataID, newOwner);
}

View File

@ -0,0 +1,47 @@
//==============================================================================
// NicePack / NiceRemoteHack
//==============================================================================
// Structure introduced for simple 'hack':
// ~ We want our replication info class to call methods that
// we would otherwise mark as 'protected';
// ~ To make this possible we introduce this structure that would can only
// be filled with valid data (non-empty name of relevant data)
// by other protected methods of this class;
// ~ Methods that that we wish only replication info to access will accept
// this structure as a parameter and only function if
// it's filled with valid data.
// ~ This way users won't be able to actually make these methods
// do any work, but replication info, that will be called from within
// with valid 'DataRef' structure, will be able to invoke them.
// ~ In addition we add the ability for this structure
// to point at a specific variable.
// ~ Such variables are marked with '#private' in comments.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceRemoteHack extends Object
abstract;
struct DataRef{
var protected string ID;
var protected string variable;
};
// Creates validation structure for data set with a given name
protected function DataRef V(string ID, optional string variable){
local DataRef validRef;
validRef.ID = ID;
validRef.variable = variable;
return validRef;
}
static function string GetDataRefID(DataRef dataRef){
return dataRef.ID;
}
static function string GetDataRefVar(DataRef dataRef){
return dataRef.variable;
}

View File

@ -0,0 +1,258 @@
//==============================================================================
// NicePack / NiceRepInfoRemoteData
//==============================================================================
// Replication info class for replicating messages needed by Storage system.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceRepInfoRemoteData extends ReplicationInfo
dependson(NiceRemoteHack);
replication{
reliable if(Role == ROLE_Authority)
ClientConnectionResponse, ClientDataExistResponse,
ClientOpenWriteRights, ClientCloseWriteRights, ClientRefuseWriteRights;
reliable if(Role < ROLE_Authority)
ServerCreateData, ServerAddListener, ServerAskDataExist,
ServerRequestWriteAccess, ServerGiveupWriteAccess;
// For sending data
reliable if(Role == ROLE_Authority)
ClientSendBool, ClientSendByte, ClientSendInt, ClientSendFloat,
ClientSendString, ClientSendClass;
reliable if(Role < ROLE_Authority)
ServerSendBool, ServerSendByte, ServerSendInt, ServerSendFloat,
ServerSendString, ServerSendClass;
}
// These variables are needed in almost every function in this class,
// so they're declared in a scope of whole class and are setup via
// 'SetupVars' call.
var string dataID;
var string dataVarName;
var NiceData remoteData;
var NiceStorageBase storage;
var NiceStorageClient storageClient;
var NiceStorageServer storageServer;
var NicePlayerController ownerPlayer;
simulated function SetupVars(NiceRemoteHack.DataRef dataRef){
dataID = class'NiceRemoteHack'.static.GetDataRefID(dataRef);
dataVarName = class'NiceRemoteHack'.static.GetDataRefVar(dataRef);
storage = class'NicePack'.static.GetStorage(level);
ownerPlayer = NicePlayerController(owner);
if(level.netMode == NM_DedicatedServer)
storageServer = NiceStorageServer(storage);
else
storageClient = NiceStorageClient(storage);
if(storage != none)
remoteData = storage.GetData(dataID);
}
function ServerSendBool(NiceRemoteHack.DataRef dataRef, bool varValue){
SetupVars(dataRef);
if(remoteData == none) return;
remoteData.SetBool(dataVarName, varValue);
}
function ServerSendByte(NiceRemoteHack.DataRef dataRef, byte varValue){
SetupVars(dataRef);
if(remoteData == none) return;
remoteData.SetByte(dataVarName, varValue);
}
function ServerSendInt(NiceRemoteHack.DataRef dataRef, int varValue){
SetupVars(dataRef);
if(remoteData == none) return;
remoteData.SetInt(dataVarName, varValue);
}
function ServerSendFloat(NiceRemoteHack.DataRef dataRef, float varValue){
SetupVars(dataRef);
if(remoteData == none) return;
remoteData.SetFloat(dataVarName, varValue);
}
function ServerSendString(NiceRemoteHack.DataRef dataRef, string varValue){
SetupVars(dataRef);
if(remoteData == none) return;
remoteData.SetString(dataVarName, varValue);
}
function ServerSendClass(NiceRemoteHack.DataRef dataRef, class<Actor> varValue){
SetupVars(dataRef);
if(remoteData == none) return;
remoteData.SetClass(dataVarName, varValue);
}
simulated function ClientSendByte( NiceRemoteHack.DataRef dataRef,
byte varValue,
bool replicationFinished){
if(level.netMode == NM_DedicatedServer) return;
// Full 'SetupVars' is an overkill
storageClient = NiceStorageClient(class'NicePack'.static.GetStorage(level));
if(storageClient == none) return;
storageClient.CheckinByte(dataRef, varValue, replicationFinished);
}
simulated function ClientSendBool( NiceRemoteHack.DataRef dataRef,
bool varValue,
bool replicationFinished){
if(level.netMode == NM_DedicatedServer) return;
// Full 'SetupVars' is an overkill
storageClient = NiceStorageClient(class'NicePack'.static.GetStorage(level));
if(storageClient == none) return;
storageClient.CheckinBool(dataRef, varValue, replicationFinished);
}
simulated function ClientSendInt( NiceRemoteHack.DataRef dataRef,
int varValue,
bool replicationFinished){
if(level.netMode == NM_DedicatedServer) return;
// Full 'SetupVars' is an overkill
storageClient = NiceStorageClient(class'NicePack'.static.GetStorage(level));
if(storageClient == none) return;
storageClient.CheckinInt(dataRef, varValue, replicationFinished);
}
simulated function ClientSendFloat( NiceRemoteHack.DataRef dataRef,
float varValue,
bool replicationFinished){
if(level.netMode == NM_DedicatedServer) return;
// Full 'SetupVars' is an overkill
storageClient = NiceStorageClient(class'NicePack'.static.GetStorage(level));
if(storageClient == none) return;
storageClient.CheckinFloat(dataRef, varValue, replicationFinished);
}
simulated function ClientSendString(NiceRemoteHack.DataRef dataRef,
string varValue,
bool replicationFinished){
if(level.netMode == NM_DedicatedServer) return;
// Full 'SetupVars' is an overkill
storageClient = NiceStorageClient(class'NicePack'.static.GetStorage(level));
if(storageClient == none) return;
storageClient.CheckinString(dataRef, varValue, replicationFinished);
}
simulated function ClientSendClass( NiceRemoteHack.DataRef dataRef,
class<Actor> varValue,
bool replicationFinished){
if(level.netMode == NM_DedicatedServer) return;
// Full 'SetupVars' is an overkill
storageClient = NiceStorageClient(class'NicePack'.static.GetStorage(level));
if(storageClient == none) return;
storageClient.CheckinClass(dataRef, varValue, replicationFinished);
}
function ServerCreateData( NiceRemoteHack.DataRef dataRef,
NiceData.EDataPriority priority){
local NiceServerData serverData;
SetupVars(dataRef);
if(ownerPlayer == none) return;
if(storageServer == none) return;
if(storageServer.CreateData(dataID, priority))
ClientConnectionResponse(dataRef, NSCDR_CREATED, true);
else{
if(remoteData != none)
// We've failed to create new data because it already exists;
ClientConnectionResponse( dataRef, NSCDR_ALREADYEXISTS,
remoteData.IsEmpty());
else
// We've failed to create new data for some other reason.
ClientConnectionResponse(dataRef, NSCDR_DOESNTEXIST, true);
}
serverData = NiceServerData(remoteData);
if(serverData != none)
serverData.AddListener(ownerPlayer);
}
function ServerAddListener(NiceRemoteHack.DataRef dataRef){
local NiceServerData serverData;
SetupVars(dataRef);
if(ownerPlayer == none) return;
if(storageServer == none) return;
serverData = NiceServerData(remoteData);
if(serverData != none){
ClientConnectionResponse( dataRef, NSCDR_CONNECTED,
serverData.IsEmpty());
}
else
ClientConnectionResponse(dataRef, NSCDR_DOESNTEXIST, true);
if(serverData != none)
serverData.AddListener(ownerPlayer);
}
function ServerAskDataExist(NiceRemoteHack.DataRef dataRef){
SetupVars(dataRef);
if(storage == none) return;
ClientDataExistResponse(dataRef, storage.DoesDataExistLocally(dataID));
}
simulated function ClientDataExistResponse( NiceRemoteHack.DataRef dataRef,
bool doesExist){
if(level.netMode == NM_DedicatedServer) return;
SetupVars(dataRef);
if(storage == none) return;
storage.events.static.CallDataExistResponse(dataID, doesExist);
}
simulated function ClientConnectionResponse
(
NiceRemoteHack.DataRef dataRef,
NiceStorageBase.ECreateDataResponse response,
bool replicationFinished
){
if(level.netMode == NM_DedicatedServer) return;
SetupVars(dataRef);
if(storageClient == none) return;
if(response != NSCDR_DOESNTEXIST)
storageClient.CheckinData(dataRef, replicationFinished);
storageClient.events.static.CallConnectionRequestResponse(dataID, response);
}
simulated function ClientOpenWriteRights(NiceRemoteHack.DataRef dataRef){
local NiceClientData clientData;
if(level.netMode == NM_DedicatedServer) return;
SetupVars(dataRef);
clientData = NiceClientData(remoteData);
if(clientData == none)
return;
clientData.SetWriteRights(dataRef, true);
storageClient.events.static.CallWriteAccessGranted(dataID, ownerPlayer);
}
simulated function ClientCloseWriteRights(NiceRemoteHack.DataRef dataRef){
local NiceClientData clientData;
if(level.netMode == NM_DedicatedServer) return;
SetupVars(dataRef);
clientData = NiceClientData(remoteData);
if(clientData == none)
return;
clientData.SetWriteRights(dataRef, false);
storageClient.events.static.CallWritingAccessRevoked(dataID, ownerPlayer);
}
simulated function ClientRefuseWriteRights(NiceRemoteHack.DataRef dataRef){
if(level.netMode == NM_DedicatedServer) return;
SetupVars(dataRef);
storageClient.events.static.CallWriteAccessRefused(dataID, ownerPlayer);
}
function ServerRequestWriteAccess(NiceRemoteHack.DataRef dataRef){
SetupVars(dataRef);
if(storageServer == none) return;
storageServer.OpenWriteAccess(dataRef, ownerPlayer);
}
function ServerGiveupWriteAccess(NiceRemoteHack.DataRef dataRef){
SetupVars(dataRef);
if(storageServer == none) return;
storageServer.CloseWriteAccess(dataRef);
}
defaultproperties
{
}

View File

@ -0,0 +1,262 @@
//==============================================================================
// NicePack / NiceServerData
//==============================================================================
// Adds data interface relevant only to server,
// as well as server implementation of more general functions.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceServerData extends NiceData
config(NicePack);
var NiceStorageServer ownerStorage;
var EDataPriority priority;
// Priority should only be set once, otherwise it can lead to issues
var bool wasPrioritySet;
// List of players who've requested replication of relevant Data set
var array<NicePlayerController> listeners;
// We can currently send server changes in this data
var protected NicePlayerController writeRightsOwner;
// Only admin players can get writing access to this data
// (but once writing access is given
// it won't close until player closes it or disconnects)
var bool isAdminOnly;
static function NiceData NewData(string newID){
local NiceData newData;
newData = new class'NiceServerData';
newData.ID = newID;
return newData;
}
function EDataPriority GetPriority(){
return priority;
}
// #private
function SetOwnerStorage( NiceRemoteHack.DataRef dataRef,
NiceStorageServerBase newOwner){
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef))
ownerStorage = NiceStorageServer(newOwner);//NICETODO: temp hack
}
// #private
function SetPriority( NiceRemoteHack.DataRef dataRef,
EDataPriority newPriority){
if(wasPrioritySet) return;
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef)){
priority = newPriority;
wasPrioritySet = true;
}
}
function NicePlayerController GetWriteRightsOwner(){
return writeRightsOwner;
}
// #private
function SetWriteRightsOwner( NiceRemoteHack.DataRef dataRef,
NicePlayerController newOwner){
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef))
writeRightsOwner = newOwner;
}
// Add 'NicePlayerController' referencing a player that should
// start listening to changes in this data set
function AddListener(NicePlayerController niceClient){
local int i;
if(ownerStorage == none) return;
if(niceClient == none || niceClient.remoteRI == none) return;
// Make sure this client isn't already added
for(i = 0;i < listeners.length;i ++)
if(listeners[i] == niceClient)
return;
listeners[listeners.length] = niceClient;
ownerStorage.AddConnection(niceClient);
// Replicate all the current data to this client
if(priority == NSP_REALTIME)
ReplicateToClient(V(ID), niceClient);
else
ownerStorage.PushDataIntoQueue(V(ID), niceClient, priority);
}
function bool IsListener(NicePlayerController niceClient){
local int i;
if(niceClient == none) return false;
for(i = 0;i < listeners.length;i ++)
if(niceClient == listeners[i])
return true;
return false;
}
// When the client disconnects - references to it's PC become 'null'.
// This function gets gets rid of them.
// #private
function PurgeNullListeners(DataRef dataRef){
local int i;
local array<NicePlayerController> newListeners;
if(dataRef.ID != ID) return;
for(i = 0;i < listeners.length;i ++)
if(listeners[i] != none)
newListeners[newListeners.length] = listeners[i];
listeners = newListeners;
}
// #private
function ReplicateToClient( NiceRemoteHack.DataRef dataRef,
NicePlayerController nicePlayer){
local int i;
if(nicePlayer == none || nicePlayer.remoteRI == none) return;
// Replication is only finished with last variable
for(i = 0;i < variables.length - 1;i ++)
ReplicateVariableToClient(V(ID), variables[i].myName, nicePlayer, false);
ReplicateVariableToClient(V(ID), variables[variables.length - 1].myName,
nicePlayer, true);
}
// #private
function ReplicateVariableToAll(NiceRemoteHack.DataRef dataRef,
string variable){
local int i;
if(ID ~= class'NiceRemoteHack'.static.GetDataRefID(dataRef)){
for(i = 0;i < listeners.length;i ++)
ReplicateVariableToClient(V(ID), variable, listeners[i], true);
}
}
// Guaranteed to check that 'niceClient' and it's 'remoteRI' are '!= none'.
// #private
function ReplicateVariableToClient( NiceRemoteHack.DataRef dataRef,
string variable,
NicePlayerController niceClient,
bool replicationFinished){
local int index;
if(niceClient == none || niceClient.remoteRI == none) return;
index = GetVariableIndex(variable);
if(index < 0)
return;
// NICETODO: change replication function based on variable's type
switch(variables[index].currentType){
case VTYPE_BOOL:
niceClient.remoteRI.ClientSendBool( V(ID, variables[index].myName),
variables[index].storedBool,
replicationFinished);
break;
case VTYPE_BYTE:
niceClient.remoteRI.ClientSendBYTE( V(ID, variables[index].myName),
variables[index].storedByte,
replicationFinished);
break;
case VTYPE_INT:
niceClient.remoteRI.ClientSendInt( V(ID, variables[index].myName),
variables[index].storedInt,
replicationFinished);
break;
case VTYPE_FLOAT:
niceClient.remoteRI.ClientSendFloat(V(ID, variables[index].myName),
variables[index].storedFloat,
replicationFinished);
break;
case VTYPE_STRING:
niceClient.remoteRI.ClientSendString(V(ID, variables[index].myName),
variables[index].storedString,
replicationFinished);
break;
case VTYPE_CLASS:
niceClient.remoteRI.ClientSendClass(V(ID, variables[index].myName),
variables[index].storedClass,
replicationFinished);
break;
default:
break;
}
}
//==============================================================================
// > Setter / getters for variables that perform necessary synchronization
function SetByte(string variableName, byte variableValue){
if(writeRightsOwner != none) return;
_SetByte(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallByteVariableUpdated(ID, variableName, variableValue);
if(priority == NSP_REALTIME)
ReplicateVariableToAll(V(ID), variableName);
else
ownerStorage.PushRequestIntoQueues(V(ID), variableName, priority);
}
function SetInt(string variableName, int variableValue){
if(writeRightsOwner != none) return;
_SetInt(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallIntVariableUpdated(ID, variableName, variableValue);
if(priority == NSP_REALTIME)
ReplicateVariableToAll(V(ID), variableName);
else
ownerStorage.PushRequestIntoQueues(V(ID), variableName, priority);
}
function SetBool(string variableName, bool variableValue){
if(writeRightsOwner != none) return;
_SetBool(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallBoolVariableUpdated(ID, variableName, variableValue);
if(priority == NSP_REALTIME)
ReplicateVariableToAll(V(ID), variableName);
else
ownerStorage.PushRequestIntoQueues(V(ID), variableName, priority);
}
function SetFloat(string variableName, float variableValue){
if(writeRightsOwner != none) return;
_SetFloat(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallFloatVariableUpdated(ID, variableName, variableValue);
if(priority == NSP_REALTIME)
ReplicateVariableToAll(V(ID), variableName);
else
ownerStorage.PushRequestIntoQueues(V(ID), variableName, priority);
}
function SetString(string variableName, string variableValue){
if(writeRightsOwner != none) return;
_SetString(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallStringVariableUpdated(ID, variableName, variableValue);
if(priority == NSP_REALTIME)
ReplicateVariableToAll(V(ID), variableName);
else
ownerStorage.PushRequestIntoQueues(V(ID), variableName, priority);
}
function SetClass(string variableName, class<Actor> variableValue){
if(writeRightsOwner != none) return;
_SetClass(V(ID, variableName), variableValue);
events.static.CallVariableUpdated(ID, variableName);
events.static.CallClassVariableUpdated(ID, variableName, variableValue);
if(priority == NSP_REALTIME)
ReplicateVariableToAll(V(ID), variableName);
else
ownerStorage.PushRequestIntoQueues(V(ID), variableName, priority);
}
defaultproperties
{
wasPrioritySet=false
}

View File

@ -0,0 +1,51 @@
//==============================================================================
// NicePack / NiceStorageBase
//==============================================================================
// Basic storage interface for creating and fetching data instances,
// relevant on both client and server.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceStorageBase extends NiceRemoteHack
abstract
config(NicePack);
var const class<NiceRemoteDataEvents> events;
// Type of actor variables used on this storage to collect data
var const class<NiceData> dataClass;
// Data collected so far
var protected array<NiceData> localStorage;
enum ECreateDataResponse{
NSCDR_CONNECTED,
NSCDR_ALREADYEXISTS,
NSCDR_CREATED,
NSCDR_DOESNTEXIST
};
function bool CreateData(string ID, NiceData.EDataPriority priority);
function bool DoesDataExistLocally(string ID){
if(GetData(ID) == none)
return false;
return true;
}
function NiceData GetData(string ID){
local int i;
for(i = 0;i < localStorage.length;i ++){
if(localStorage[i] == none) continue;
if(localStorage[i].GetID() ~= ID)
return localStorage[i];
}
return none;
}
defaultproperties
{
dataClass=class'NiceData'
events=class'NiceRemoteDataEvents'
}

View File

@ -0,0 +1,191 @@
//==============================================================================
// NicePack / NiceStorageClient
//==============================================================================
// Implements storage methods relevant only to client.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceStorageClient extends NiceStorageBase
config(NicePack);
var NiceRepInfoRemoteData remoteRI;
function bool ConnectData(string ID){
if(ID == "") return false;
if(remoteRI == none) return false;
remoteRI.ServerAddListener(V(ID));
return true;
}
function bool IsLinkEstablished(){
return (remoteRI == none);
}
// Requests a creation of remote data storage on server.
function bool CreateData(string ID, NiceData.EDataPriority priority){
if(ID == "") return false;
if(remoteRI == none) return false;
if(DoesDataExistLocally(ID)) return false;
remoteRI.ServerCreateData(V(ID), priority);
return true;
}
// Checks if server has data with a given name.
// Responds via calling 'DataExistResponse' event.
function DoesDataExistOnServer(string dataID){
if(remoteRI == none) return;
if(DoesDataExistLocally(dataID))
events.static.CallDataExistResponse(dataID, true);
else
remoteRI.ServerAskDataExist(V(dataID));
}
// Must be already connected to data to do this
function bool RequestWriteAccess(string dataID){
if(remoteRI == none) return false;
if(!DoesDataExistLocally(dataID)) return false;
remoteRI.ServerRequestWriteAccess(V(dataID));
return true;
}
function bool GiveupWriteAccess(string dataID){
local NiceClientData data;
if(remoteRI == none) return false;
if(!DoesDataExistLocally(dataID)) return false;
data = NiceClientData(GetData(dataID));
if(data == none || !data.HasWriteRights())
return false;
data.SetWriteRights(V(dataID), false);
remoteRI.ServerGiveupWriteAccess(V(dataID));
return true;
}
// #private
function CheckinData(DataRef dataRef, bool replicationFinished){
local NiceClientData clientData;
// This shouldn't happen, but just in case
if(DoesDataExistLocally(dataRef.ID)) return;
// Create data as requested
clientData =
NiceClientData(class'NiceClientData'.static.NewData(dataRef.ID));
if(clientData == none)
return;
localStorage[localStorage.length] = clientData;
clientData.SetOwnerStorage(dataRef, self);
clientData.SetUpToDate(dataRef, replicationFinished);
}
// #private
function CheckinBool(DataRef dataRef, bool value, bool replicationFinished){
local NiceClientData clientData;
clientData = NiceClientData(GetData(dataRef.ID));
if(clientData == none)
return;
clientData.SetUpToDate(dataRef, replicationFinished);
clientData._SetBool(dataRef, value);
// Events
events.static.CallVariableUpdated(dataRef.ID, dataRef.variable);
events.static.CallBoolVariableUpdated(dataRef.ID, dataRef.variable, value);
if(replicationFinished)
events.static.CallDataUpToDate(dataRef.ID);
}
function CheckinByte(DataRef dataRef, byte value, bool replicationFinished){
local NiceClientData clientData;
clientData = NiceClientData(GetData(dataRef.ID));
if(clientData == none)
return;
clientData.SetUpToDate(dataRef, replicationFinished);
clientData._SetByte(dataRef, value);
// Events
events.static.CallVariableUpdated(dataRef.ID, dataRef.variable);
events.static.CallByteVariableUpdated(dataRef.ID, dataRef.variable, value);
if(replicationFinished)
events.static.CallDataUpToDate(dataRef.ID);
}
function CheckinInt(DataRef dataRef, int value, bool replicationFinished){
local NiceClientData clientData;
clientData = NiceClientData(GetData(dataRef.ID));
if(clientData == none)
return;
clientData.SetUpToDate(dataRef, replicationFinished);
clientData._SetInt(dataRef, value);
// Events
events.static.CallVariableUpdated(dataRef.ID, dataRef.variable);
events.static.CallIntVariableUpdated(dataRef.ID, dataRef.variable, value);
if(replicationFinished)
events.static.CallDataUpToDate(dataRef.ID);
}
function CheckinFloat(DataRef dataRef, float value, bool replicationFinished){
local NiceClientData clientData;
clientData = NiceClientData(GetData(dataRef.ID));
if(clientData == none)
return;
clientData.SetUpToDate(dataRef, replicationFinished);
clientData._SetFloat(dataRef, value);
// Events
events.static.CallVariableUpdated(dataRef.ID, dataRef.variable);
events.static.CallFloatVariableUpdated(dataRef.ID, dataRef.variable, value);
if(replicationFinished)
events.static.CallDataUpToDate(dataRef.ID);
}
function CheckinString(DataRef dataRef, string value, bool replicationFinished){
local NiceClientData clientData;
clientData = NiceClientData(GetData(dataRef.ID));
if(clientData == none)
return;
clientData.SetUpToDate(dataRef, replicationFinished);
clientData._SetString(dataRef, value);
// Events
events.static.CallVariableUpdated(dataRef.ID, dataRef.variable);
events.static.CallStringVariableUpdated(dataRef.ID, dataRef.variable,
value);
if(replicationFinished)
events.static.CallDataUpToDate(dataRef.ID);
}
function CheckinClass( DataRef dataRef, class<Actor> value,
bool replicationFinished){
local NiceClientData clientData;
clientData = NiceClientData(GetData(dataRef.ID));
if(clientData == none)
return;
clientData.SetUpToDate(dataRef, replicationFinished);
clientData._SetClass(dataRef, value);
// Events
events.static.CallVariableUpdated(dataRef.ID, dataRef.variable);
events.static.CallClassVariableUpdated(dataRef.ID, dataRef.variable, value);
if(replicationFinished)
events.static.CallDataUpToDate(dataRef.ID);
}
// NICETODO: to debug, remove later
function Print(NicePlayerController pc){
local int i, j;
local array<string> names;
for(i = 0;i < localStorage.length;i ++){
pc.ClientMessage("Data:"@localStorage[i].GetID());
names = localStorage[i].GetVariableNames();
for(j = 0;j < names.length;j ++){
pc.ClientMessage(">" @ names[j] @ " = " @ String(localStorage[i].GetInt(names[j])));
}
}
}
defaultproperties
{
dataClass=class'NiceClientData'
}

View File

@ -0,0 +1,224 @@
//==============================================================================
// NicePack / NiceStorageServer
//==============================================================================
// Implements queue-related storage methods relevant only to server.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceStorageServer extends NiceStorageServerBase
config(NicePack);
function bool CanGrantWriteRights( NiceServerData data,
NicePlayerController clientRef){
if(!super.CanGrantWriteRights(data, clientRef))
return false;
if(HasPendingChanges(data.GetID(), clientRef))
return false;
return true;
}
// Checks if given data has some changes not yet replicated to the player.
// Works only on a server.
function bool HasPendingChanges(string dataID,
NicePlayerController nicePlayer){
local NiceServerData dataToCheck;
local int connectionIndex;
local ClientConnection connection;
connectionIndex = FindConnection(nicePlayer);
if(connectionIndex < 0)
return false;
connection = connections[connectionIndex];
dataToCheck = NiceServerData(GetData(dataID));
if(dataToCheck == none)
return false;
switch(dataToCheck.priority){
case NSP_REALTIME:
return false;
case NSP_HIGH:
return HasPendingChangesInQueue(dataID,
connection.highPriorityQueue);
default:
return HasPendingChangesInQueue(dataID,
connection.lowPriorityQueue);
}
return false;
}
protected function bool HasPendingChangesInQueue( string dataID,
RequestQueue queue){
local int i;
for(i = queue.newIndex;i < queue.requests.length;i ++)
if(queue.requests[i].dataID == dataID)
return true;
return false;
}
protected function bool DoesQueueContainRequest
(
RequestQueue queue,
ReplicationRequest request
){
local int i;
for(i = queue.newIndex;i < queue.requests.length;i ++)
if(queue.requests[i] == request)
return true;
return false;
}
// Replicates most pressing request for given connection.
// Returns 'true' if we were able to replicate something.
protected function bool ReplicateTopConnectionRequest
(
NicePlayerController clientRef
){
local int queueLength;
local int connectionIndex;
local ClientConnection connectionCopy;
connectionIndex = FindConnection(clientRef);
if(connectionIndex < 0)
return false;
connectionCopy = connections[connectionIndex];
// Try high priority queue
queueLength = connectionCopy.highPriorityQueue.requests.length -
connectionCopy.highPriorityQueue.newIndex;
if(queueLength > 0){
ReplicateTopQueueRequest(clientRef, connectionCopy.highPriorityQueue);
connections[connectionIndex] = connectionCopy;
return true;
}
// Then, if high-priority one was empty, try low priority queue
queueLength = connectionCopy.lowPriorityQueue.requests.length -
connectionCopy.lowPriorityQueue.newIndex;
if(queueLength > 0){
ReplicateTopQueueRequest(clientRef, connectionCopy.lowPriorityQueue);
connections[connectionIndex] = connectionCopy;
return true;
}
return false;
}
// Replicates top request of given queue and removes former from the latter.
// - Requires queue to be non-empty.
// - Doesn't check if client and queue are related.
protected function ReplicateTopQueueRequest(NicePlayerController clientRef,
out RequestQueue queue){
local ReplicationRequest request;
local NiceServerData dataToReplicate;
local bool replicationFinished;
request = queue.requests[queue.newIndex];
dataToReplicate = NiceServerData(GetData(request.dataID));
if(dataToReplicate == none)
return;
// Update queue index first, so that 'HasPendingChanges'
// can return an up-to-date result.
queue.newIndex ++;
replicationFinished = !HasPendingChanges( dataToReplicate.GetID(),
clientRef);
dataToReplicate.ReplicateVariableToClient( V(request.dataID),
request.variable, clientRef,
replicationFinished);
// Preserve invariant
if(queue.newIndex >= queue.requests.length){
queue.newIndex = 0;
queue.requests.length = 0;
}
}
protected function PushRequestToConnection
( ReplicationRequest request,
NicePlayerController clientRef,
NiceData.EDataPriority priority
){
local int connectionIndex;
local RequestQueue givenQueue;
local ClientConnection connectionCopy;
if(priority == NSP_REALTIME) return;
connectionIndex = FindConnection(clientRef);
if(connectionIndex < 0)
return;
connectionCopy = connections[connectionIndex];
// Use appropriate queue
switch(priority){
case NSP_HIGH:
givenQueue = connectionCopy.highPriorityQueue;
if(!DoesQueueContainRequest(givenQueue, request)){
connectionCopy.highPriorityQueue.
requests[givenQueue.requests.length] = request;
}
break;
case NSP_LOW:
givenQueue = connectionCopy.lowPriorityQueue;
if(!DoesQueueContainRequest(givenQueue, request)){
connectionCopy.lowPriorityQueue.
requests[givenQueue.requests.length] = request;
}
break;
default:
return;
}
connections[connectionIndex] = connectionCopy;
}
// Pushes requests to replicate variable change to all active connections
// #private
function PushRequestIntoQueues( NiceRemoteHack.DataRef dataRef,
string variableName,
NiceData.EDataPriority priority){
local int i;
local NiceServerData data;
local ReplicationRequest request;
data = NiceServerData(GetData(dataRef.ID));
if(data == none)
return;
request.dataID = data.GetID();
request.variable = variableName;
for(i = 0;i < connections.length;i ++)
if(data.IsListener(connections[i].player))
PushRequestToConnection(request, connections[i].player, priority);
}
// Pushes requests necessary to perform initial replication
// of given 'updatedData' to given 'nicePlayer'
// #private
function PushDataIntoQueue( NiceRemoteHack.DataRef dataRef,
NicePlayerController clientRef,
NiceData.EDataPriority priority){
local int i;
local NiceServerData dataToPush;
local ReplicationRequest request;
local array<string> dataVariables;
dataToPush = NiceServerData(GetData(dataRef.ID));
if(dataToPush == none)
return;
request.dataID = dataToPush.GetID();
dataVariables = dataToPush.GetVariableNames();
for(i = 0;i < dataVariables.length;i ++){
request.variable = dataVariables[i];
PushRequestToConnection(request, clientRef, priority);
}
}
function Tick(float delta){
local int i;
local bool didReplicate;
for(i = 0;i < connections.length;i ++){
if(connections[i].replicationCountdown > 0)
connections[i].replicationCountdown -= delta;
if(connections[i].replicationCountdown <= 0.0){
didReplicate = ReplicateTopConnectionRequest(connections[i].player);
if(didReplicate)
connections[i].replicationCountdown = replicationCooldown;
}
}
}
defaultproperties
{
}

View File

@ -0,0 +1,206 @@
//==============================================================================
// NicePack / NiceStorageServerBase
//==============================================================================
// Implements storage methods relevant only to server.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceStorageServerBase extends NiceStorageBase
abstract
config(NicePack);
struct ReplicationRequest{
var string dataID;
var string variable;
};
struct RequestQueue{
// Elements with indices below this one were already replicated
var int newIndex;
var array<ReplicationRequest> requests;
// All changes must preserve following invariants:
// - newIndex >= 0
// - newIndex <= requests.length
};
struct ClientConnection{
var NicePlayerController player;
var float replicationCountdown;
var RequestQueue lowPriorityQueue;
var RequestQueue highPriorityQueue;
};
// List of all the players who are connected to any of our data
var protected array<ClientConnection> connections;
// How much time needs to pass before we send new data;
// Each client has it's own cooldowns;
// Not applicable to 'NSP_REALTIME' priority
// since everything is replicated immediately then.
var config float replicationCooldown;
//==============================================================================
// > Variables related to purging 'none' actors
// After client disconnects - it's reference will only uselessly
// clutter connection or listeners references, -
// that's why we need to do periodic "clean ups".
// Time between purges
var config float cleanupCooldown;
// We clear all lost connections every purge, but only this many data sets
var config int cleanupPassesPerRound;
var protected float cleanupCountDown;
// Next index of the next data to be cleaned
var protected int cleanupNextDataIndex;
function bool CreateData(string ID, NiceData.EDataPriority priority){
local NiceServerData serverData;
if(ID == "") return false;
if(DoesDataExistLocally(ID)) return false;
serverData = NiceServerData(class'NiceServerData'.static.NewData(ID));
if(!StoreData(serverData, priority))
return false;
return true;
}
// Puts given with data in the storage without any synchronization work.
// Can fail if data with the same ID already exists.
function bool StoreData(NiceData data, NiceData.EDataPriority priority){
local string ID;
local NiceServerData serverData;
serverData = NiceServerData(data);
if(serverData == none) return false;
ID = serverData.GetID();
if(DoesDataExistLocally(ID))
return false;
localStorage[localStorage.length] = serverData;
serverData.SetOwnerStorage(V(ID), self);
serverData.SetPriority(V(ID), priority);
events.static.CallDataCreated(ID);
return true;
}
function bool CanGrantWriteRights( NiceServerData data,
NicePlayerController clientRef){
local bool isClientAdmin;
if(data == none) return false;
if(data.GetWriteRightsOwner() != none) return false;
// Admin rights check
isClientAdmin = false;
if(clientRef != none && clientRef.PlayerReplicationInfo != none)
isClientAdmin = clientRef.PlayerReplicationInfo.bAdmin;
if(data.isAdminOnly && !isClientAdmin)
return false;
return true;
}
// #private
function bool OpenWriteAccess(DataRef dataRef, NicePlayerController niceClient){
local NiceServerData data;
if(niceClient == none || niceClient.remoteRI == none) return false;
data = NiceServerData(GetData(dataRef.ID));
if(data == none)
return false;
if(CanGrantWriteRights(data, niceClient)){
data.SetWriteRightsOwner(dataRef, niceClient);
events.static.CallWriteAccessGranted(dataRef.ID, niceClient);
niceClient.remoteRI.ClientOpenWriteRights(dataRef);
return true;
}
events.static.CallWriteAccessRefused( dataRef.ID,
data.GetWriteRightsOwner());
niceClient.remoteRI.ClientRefuseWriteRights(dataRef);
return false;
}
// #private
function bool CloseWriteAccess(DataRef dataRef){
local NiceServerData data;
local NicePlayerController oldOwner;
data = NiceServerData(GetData(dataRef.ID));
if(data == none)
return false;
oldOwner = data.GetWriteRightsOwner();
if(oldOwner == none)
return false;
data.SetWriteRightsOwner(dataRef, none);
events.static.CallWritingAccessRevoked(dataRef.ID, oldOwner);
if(oldOwner.remoteRI != none)
oldOwner.remoteRI.ClientCloseWriteRights(dataRef);
return true;
}
function AddConnection(NicePlayerController clientRef){
local int i;
local int newIndex;
local ClientConnection newConnection;
if(clientRef == none) return;
for(i = 0;i < connections.length;i ++)
if(connections[i].player == clientRef)
return;
newConnection.player = clientRef;
newConnection.lowPriorityQueue.newIndex = 0;
newConnection.highPriorityQueue.newIndex = 0;
newIndex = connections.length;
connections[newIndex] = newConnection;
}
// Returns index for a connection for 'clientRef',
// returns -1 if there's no connection for it.
protected function int FindConnection(NicePlayerController clientRef){
local int i;
// Connection can contain 'none' values due to players disconnecting,
if(clientRef == none)
return -1;
for(i = 0;i < connections.length;i ++)
if(connections[i].player == clientRef)
return i;
return -1;
}
protected function CleanupConnections(){
local int i;
local array<ClientConnection> newConnections;
for(i = 0;i < connections.length;i ++)
if(connections[i].player != none)
newConnections[newConnections.length] = connections[i];
connections = newConnections;
}
// There might be a potentially huge number of data with listeners,
// so we'll clean only a certain amount of the at a time.
protected function DoCleanupListenersRound(int passesAmount){
local NiceServerData serverData;
if(localStorage.length <= 0) return;
if(cleanupNextDataIndex < 0 || cleanupNextDataIndex >= localStorage.length)
cleanupNextDataIndex = 0;
serverData = NiceServerData(localStorage[cleanupNextDataIndex]);
if(serverData != none)
serverData.PurgeNullListeners(V(serverData.GetID()));
cleanupNextDataIndex ++;
DoCleanupListenersRound(passesAmount - 1);
}
function Tick(float delta){
cleanupCountDown -= delta;
if(cleanupCountDown <= 0){
cleanupCountDown = cleanupCooldown;
CleanupConnections();
DoCleanupListenersRound(cleanupPassesPerRound);
}
}
defaultproperties
{
dataClass=class'NiceServerData'
cleanupCooldown=1.0
cleanupPassesPerRound=10
replicationCooldown=0.025
}

View File

@ -0,0 +1,19 @@
//==============================================================================
// NicePack / NiceArchivator
//==============================================================================
// "Compresses" and "decompresses" parts of NicePlain data into
// string for replication.
//==============================================================================
// Class hierarchy: Object > NiceArchivator
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceArchivator extends Object;
defaultproperties
{
}

View File

@ -0,0 +1,34 @@
//==============================================================================
// NicePack / NiceDictionary
//==============================================================================
// Stores pair of variable names and their shorteners for `NiceArchivator`.
//==============================================================================
// Class hierarchy: Object > NiceDictionary
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceDictionary extends Object
abstract;
struct Definition
{
var string fullName;
var string shortName;
};
var public const array<Definition> definitions;
defaultproperties
{
definitions(0)=(fullName="Location",shortName="L")
definitions(1)=(fullName="Momentum",shortName="M")
definitions(2)=(fullName="HeadshotLevel",shortName="H")
definitions(3)=(fullName="Damage",shortName="D")
definitions(4)=(fullName="LockonTime",shortName="T")
definitions(5)=(fullName="Spread",shortName="S")
definitions(6)=(fullName="ContiniousFire",shortName="C")
}

View File

@ -0,0 +1,183 @@
//==============================================================================
// NicePack / NicePlainData
//==============================================================================
// Provides functionality for local data storage of named variables for
// following types:
// bool, byte, int, float, string, class<Object>.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NicePlainData extends Object;
struct DataPair{
var string key;
var string value;
};
struct Data{
var array<DataPair> pairs;
};
// Returns index of variable with name 'varName', returns -1 if no entry found
static function int LookupVar(Data mySet, string varName){
local int i;
for(i = 0;i < mySet.pairs.length;i ++)
if(mySet.pairs[i].key ~= varName)
return i;
return -1;
}
static function bool GetBool( Data mySet,
string varName,
optional bool defaultValue){
local int index;
index = LookupVar(mySet, varName);
if(index < 0)
return defaultValue;
else
return bool(mySet.pairs[index].value);
}
static function SetBool(out Data mySet, string varName, bool varValue){
local int index;
local DataPair newPair;
index = LookupVar(mySet, varName);
if(index < 0){
newPair.key = varName;
newPair.value = string(varValue);
mySet.pairs[mySet.pairs.length] = newPair;
}
else
mySet.pairs[index].value = string(varValue);
}
static function byte GetByte( Data mySet,
string varName,
optional byte defaultValue){
local int index;
index = LookupVar(mySet, varName);
if(index < 0)
return defaultValue;
else
return byte(mySet.pairs[index].value);
}
static function SetByte(out Data mySet, string varName, byte varValue){
local int index;
local DataPair newPair;
index = LookupVar(mySet, varName);
if(index < 0){
newPair.key = varName;
newPair.value = string(varValue);
mySet.pairs[mySet.pairs.length] = newPair;
}
else
mySet.pairs[index].value = string(varValue);
}
static function int GetInt( Data mySet,
string varName,
optional int defaultValue){
local int index;
index = LookupVar(mySet, varName);
if(index < 0)
return defaultValue;
else
return int(mySet.pairs[index].value);
}
static function SetInt(out Data mySet, string varName, int varValue){
local int index;
local DataPair newPair;
index = LookupVar(mySet, varName);
if(index < 0){
newPair.key = varName;
newPair.value = string(varValue);
mySet.pairs[mySet.pairs.length] = newPair;
}
else
mySet.pairs[index].value = string(varValue);
}
static function float GetFloat( Data mySet,
string varName,
optional float defaultValue){
local int index;
index = LookupVar(mySet, varName);
if(index < 0)
return defaultValue;
else
return float(mySet.pairs[index].value);
}
static function SetFloat(out Data mySet, string varName, float varValue){
local int index;
local DataPair newPair;
index = LookupVar(mySet, varName);
if(index < 0){
newPair.key = varName;
newPair.value = string(varValue);
mySet.pairs[mySet.pairs.length] = newPair;
}
else
mySet.pairs[index].value = string(varValue);
}
static function string GetString( Data mySet,
string varName,
optional string defaultValue){
local int index;
index = LookupVar(mySet, varName);
if(index < 0)
return defaultValue;
else
return mySet.pairs[index].value;
}
static function SetString(out Data mySet, string varName, string varValue){
local int index;
local DataPair newPair;
index = LookupVar(mySet, varName);
if(index < 0){
newPair.key = varName;
newPair.value = varValue;
mySet.pairs[mySet.pairs.length] = newPair;
}
else
mySet.pairs[index].value = varValue;
}
static function class<Object> GetClass( Data mySet,
string varName,
optional class<Object> defaultValue){
local int index;
local string className;
index = LookupVar(mySet, varName);
if(index < 0)
return defaultValue;
className = mySet.pairs[index].value;
return class<Object>(DynamicLoadObject(className, class'Class'));
}
static function SetClass( out Data mySet,
string varName,
optional class<Object> varValue){
local int index;
local DataPair newPair;
index = LookupVar(mySet, varName);
if(index < 0){
newPair.key = varName;
newPair.value = string(varValue);
mySet.pairs[mySet.pairs.length] = newPair;
}
else
mySet.pairs[index].value = string(varValue);
}
defaultproperties
{
}

View File

@ -0,0 +1,4 @@
class NiceBlockHitEmitter extends MetalHitEmitter;
defaultproperties
{ ImpactSounds(0)=None ImpactSounds(1)=None ImpactSounds(2)=None RemoteRole=ROLE_SimulatedProxy
}

View File

@ -0,0 +1,5 @@
// ScrN copy
class NiceFreezeParticlesBase extends Emitter;
defaultproperties
{ bNoDelete=False
}

View File

@ -0,0 +1,8 @@
// ScrN copy
class NiceFreezeParticlesDirectional extends NiceFreezeParticlesBase;
simulated function Trigger(Actor other, Pawn eventInstigator){
emitters[0].SpawnParticle(1);
}
defaultproperties
{ Style=STY_Additive bHardAttach=True bDirectional=True
}

View File

@ -0,0 +1,21 @@
class NiceIceChunkEmitter extends Emitter;
var() array<Sound> ImpactSounds;
simulated function PostBeginPlay(){
if(ImpactSounds.Length > 0)
PlaySound(ImpactSounds[Rand(ImpactSounds.Length)]);
}
// NICETODO: change linksfrom HTeac_A to NicePackSM (and change that file)
defaultproperties
{ ImpactSounds(0)=Sound'KFWeaponSound.bullethitglass' ImpactSounds(1)=Sound'KFWeaponSound.bullethitglass2' Begin Object Class=MeshEmitter Name=MeshEmitter0 StaticMesh=StaticMesh'HTec_A.IceChunk1' UseCollision=True RespawnDeadParticles=False SpinParticles=True DampRotation=True UniformSize=True AutomaticInitialSpawning=False Acceleration=(Z=-1000.000000) DampingFactorRange=(X=(Min=0.200000,Max=0.200000),Y=(Min=0.200000,Max=0.200000),Z=(Min=0.200000,Max=0.200000)) 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)) MaxParticles=5 SpinsPerSecondRange=(X=(Max=1.000000),Y=(Max=1.000000),Z=(Max=1.000000)) StartSpinRange=(X=(Min=-1.000000,Max=1.000000),Y=(Min=-1.000000,Max=1.000000),Z=(Min=-1.000000,Max=1.000000)) RotationDampingFactorRange=(X=(Min=0.200000,Max=0.200000),Y=(Min=0.200000,Max=0.200000),Z=(Min=0.200000,Max=0.200000)) StartSizeRange=(X=(Min=5.000000,Max=8.000000),Y=(Min=5.000000,Max=8.000000),Z=(Min=5.000000,Max=8.000000)) InitialParticlesPerSecond=10000.000000 StartVelocityRange=(X=(Min=-75.000000,Max=75.000000),Y=(Min=-75.000000,Max=75.000000),Z=(Min=-100.000000,Max=300.000000)) End Object Emitters(0)=MeshEmitter'NicePack.NiceIceChunkEmitter.MeshEmitter0'
Begin Object Class=MeshEmitter Name=MeshEmitter2 StaticMesh=StaticMesh'HTec_A.IceChunk2' UseCollision=True RespawnDeadParticles=False SpinParticles=True DampRotation=True UniformSize=True AutomaticInitialSpawning=False Acceleration=(Z=-1000.000000) DampingFactorRange=(X=(Min=0.200000,Max=0.200000),Y=(Min=0.200000,Max=0.200000),Z=(Min=0.200000,Max=0.200000)) 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)) MaxParticles=8 DetailMode=DM_High SpinsPerSecondRange=(X=(Max=1.000000),Y=(Max=1.000000),Z=(Max=1.000000)) StartSpinRange=(X=(Min=-1.000000,Max=1.000000),Y=(Min=-1.000000,Max=1.000000),Z=(Min=-1.000000,Max=1.000000)) RotationDampingFactorRange=(X=(Min=0.200000,Max=0.200000),Y=(Min=0.200000,Max=0.200000),Z=(Min=0.200000,Max=0.200000)) StartSizeRange=(X=(Min=3.000000,Max=6.000000),Y=(Min=3.000000,Max=6.000000),Z=(Min=3.000000,Max=6.000000)) InitialParticlesPerSecond=10000.000000 StartVelocityRange=(X=(Min=-150.000000,Max=150.000000),Y=(Min=-150.000000,Max=150.000000),Z=(Min=-100.000000,Max=500.000000)) End Object Emitters(1)=MeshEmitter'NicePack.NiceIceChunkEmitter.MeshEmitter2'
Begin Object Class=MeshEmitter Name=MeshEmitter3 StaticMesh=StaticMesh'HTec_A.IceChunk3' UseCollision=True RespawnDeadParticles=False SpinParticles=True DampRotation=True UniformSize=True AutomaticInitialSpawning=False Acceleration=(Z=-1000.000000) DampingFactorRange=(X=(Min=0.200000,Max=0.200000),Y=(Min=0.200000,Max=0.200000),Z=(Min=0.200000,Max=0.200000)) 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)) MaxParticles=12 DetailMode=DM_High SpinsPerSecondRange=(X=(Max=1.000000),Y=(Max=1.000000),Z=(Max=1.000000)) StartSpinRange=(X=(Min=-1.000000,Max=1.000000),Y=(Min=-1.000000,Max=1.000000),Z=(Min=-1.000000,Max=1.000000)) RotationDampingFactorRange=(X=(Min=0.200000,Max=0.200000),Y=(Min=0.200000,Max=0.200000),Z=(Min=0.200000,Max=0.200000)) StartSizeRange=(X=(Min=2.000000,Max=5.000000),Y=(Min=2.000000,Max=5.000000),Z=(Min=2.000000,Max=5.000000)) InitialParticlesPerSecond=10000.000000 StartVelocityRange=(X=(Min=-200.000000,Max=200.000000),Y=(Min=-200.000000,Max=200.000000),Z=(Min=-100.000000,Max=500.000000)) End Object Emitters(2)=MeshEmitter'NicePack.NiceIceChunkEmitter.MeshEmitter3'
Begin Object Class=SpriteEmitter Name=SpriteEmitter8 UseCollision=True FadeOut=True FadeIn=True RespawnDeadParticles=False UniformSize=True AutomaticInitialSpawning=False UseRandomSubdivision=True Acceleration=(Z=-1000.000000) ExtentMultiplier=(X=0.000000,Y=0.000000,Z=0.000000) DampingFactorRange=(X=(Min=0.250000,Max=0.250000),Y=(Min=0.250000,Max=0.250000),Z=(Min=0.250000,Max=0.250000)) 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.500000 MaxParticles=55 DetailMode=DM_SuperHigh UseRotationFrom=PTRS_Actor StartSizeRange=(X=(Min=0.700000,Max=1.700000)) InitialParticlesPerSecond=10000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'Effects_Tex.BulletHits.snowchunksfinal' TextureUSubdivisions=2 TextureVSubdivisions=2 LifetimeRange=(Min=1.400000,Max=1.400000) StartVelocityRange=(X=(Min=-200.000000,Max=200.000000),Y=(Min=-200.000000,Max=200.000000),Z=(Min=-300.000000,Max=350.000000)) End Object Emitters(3)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter8'
Begin Object Class=SpriteEmitter Name=SpriteEmitter9 ProjectionNormal=(Y=1.000000,Z=0.000000) FadeOut=True FadeIn=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False Acceleration=(Z=-1000.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)) Opacity=0.500000 FadeOutStartTime=0.442500 FadeInEndTime=0.007500 MaxParticles=25 DetailMode=DM_High UseRotationFrom=PTRS_Actor SpinCCWorCW=(X=0.000000) SpinsPerSecondRange=(X=(Max=0.300000)) StartSpinRange=(X=(Min=-0.300000,Max=0.300000)) SizeScale(0)=(RelativeSize=0.400000) SizeScale(1)=(RelativeTime=0.500000,RelativeSize=0.700000) SizeScale(2)=(RelativeTime=1.000000,RelativeSize=1.300000) StartSizeRange=(X=(Min=20.000000,Max=40.000000),Y=(Min=20.000000,Max=40.000000),Z=(Min=20.000000,Max=40.000000)) InitialParticlesPerSecond=10000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'Effects_Tex.BulletHits.watersplatter2' TextureUSubdivisions=2 TextureVSubdivisions=2 LifetimeRange=(Min=0.750000,Max=0.750000) StartVelocityRange=(X=(Min=-150.000000,Max=150.000000),Y=(Min=-150.000000,Max=150.000000),Z=(Min=-25.000000,Max=300.000000)) End Object Emitters(4)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter9'
Begin Object Class=SpriteEmitter Name=SpriteEmitter10 ProjectionNormal=(Y=1.000000,Z=0.000000) FadeOut=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True Acceleration=(Z=-15.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)) Opacity=0.250000 FadeOutStartTime=0.175000 MaxParticles=5 StartLocationRange=(X=(Min=10.000000,Max=10.000000)) AddLocationFromOtherEmitter=0 UseRotationFrom=PTRS_Actor SpinCCWorCW=(X=0.000000) SpinsPerSecondRange=(X=(Max=0.200000)) StartSpinRange=(X=(Min=-0.300000,Max=0.300000)) SizeScale(0)=(RelativeSize=0.400000) SizeScale(1)=(RelativeTime=0.560000,RelativeSize=1.000000) StartSizeRange=(X=(Min=6.000000,Max=60.000000),Y=(Min=6.000000,Max=60.000000),Z=(Min=6.000000,Max=60.000000)) InitialParticlesPerSecond=1.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'kf_fx_trip_t.Misc.smoke_animated' TextureUSubdivisions=8 TextureVSubdivisions=8 LifetimeRange=(Min=0.350000,Max=0.350000) End Object Emitters(5)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter10'
Begin Object Class=SpriteEmitter Name=SpriteEmitter11 ProjectionNormal=(Y=1.000000,Z=0.000000) FadeOut=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True Acceleration=(Z=-15.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)) Opacity=0.250000 FadeOutStartTime=0.175000 MaxParticles=8 StartLocationRange=(X=(Min=10.000000,Max=10.000000)) AddLocationFromOtherEmitter=1 UseRotationFrom=PTRS_Actor SpinCCWorCW=(X=0.000000) SpinsPerSecondRange=(X=(Max=0.200000)) StartSpinRange=(X=(Min=-0.300000,Max=0.300000)) SizeScale(0)=(RelativeSize=0.400000) SizeScale(1)=(RelativeTime=0.560000,RelativeSize=1.000000) StartSizeRange=(X=(Min=6.000000,Max=60.000000),Y=(Min=6.000000,Max=60.000000),Z=(Min=6.000000,Max=60.000000)) InitialParticlesPerSecond=1.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'kf_fx_trip_t.Misc.smoke_animated' TextureUSubdivisions=8 TextureVSubdivisions=8 LifetimeRange=(Min=0.350000,Max=0.350000) End Object Emitters(6)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter11'
Begin Object Class=SpriteEmitter Name=SpriteEmitter12 ProjectionNormal=(Y=1.000000,Z=0.000000) FadeOut=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True Acceleration=(Z=-15.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)) Opacity=0.250000 FadeOutStartTime=0.175000 MaxParticles=12 DetailMode=DM_High StartLocationRange=(X=(Min=10.000000,Max=10.000000)) AddLocationFromOtherEmitter=2 UseRotationFrom=PTRS_Actor SpinCCWorCW=(X=0.000000) SpinsPerSecondRange=(X=(Max=0.200000)) StartSpinRange=(X=(Min=-0.300000,Max=0.300000)) SizeScale(0)=(RelativeSize=0.400000) SizeScale(1)=(RelativeTime=0.560000,RelativeSize=1.000000) StartSizeRange=(X=(Min=6.000000,Max=60.000000),Y=(Min=6.000000,Max=60.000000),Z=(Min=6.000000,Max=60.000000)) InitialParticlesPerSecond=1.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'kf_fx_trip_t.Misc.smoke_animated' TextureUSubdivisions=8 TextureVSubdivisions=8 LifetimeRange=(Min=0.350000,Max=0.350000) End Object Emitters(7)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter12'
Begin Object Class=SpriteEmitter Name=SpriteEmitter13 ProjectionNormal=(Y=1.000000,Z=0.000000) FadeOut=True FadeIn=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False Acceleration=(Z=-1000.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)) Opacity=0.250000 FadeOutStartTime=0.442500 FadeInEndTime=0.007500 MaxParticles=12 StartLocationRange=(X=(Min=20.000000,Max=20.000000)) UseRotationFrom=PTRS_Actor SpinCCWorCW=(X=0.000000) SpinsPerSecondRange=(X=(Max=0.300000)) StartSpinRange=(X=(Min=-0.300000,Max=0.300000)) SizeScale(0)=(RelativeSize=0.400000) SizeScale(1)=(RelativeTime=0.500000,RelativeSize=0.900000) SizeScale(2)=(RelativeTime=1.000000,RelativeSize=1.300000) StartSizeRange=(X=(Min=25.000000,Max=45.000000),Y=(Min=25.000000,Max=45.000000),Z=(Min=25.000000,Max=45.000000)) InitialParticlesPerSecond=10000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'Effects_Tex.BulletHits.watersplashcloud' TextureUSubdivisions=1 TextureVSubdivisions=1 LifetimeRange=(Min=0.750000,Max=0.750000) StartVelocityRange=(X=(Min=-150.000000,Max=150.000000),Y=(Min=-150.000000,Max=150.000000),Z=(Min=-5.000000,Max=150.000000)) End Object Emitters(8)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter13'
Begin Object Class=SpriteEmitter Name=SpriteEmitter14 ProjectionNormal=(Y=1.000000,Z=0.000000) FadeOut=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False Acceleration=(Z=-22.000000) DampingFactorRange=(X=(Min=0.250000,Max=0.250000),Y=(Min=0.250000,Max=0.250000),Z=(Min=0.250000,Max=0.250000)) 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)) Opacity=0.500000 FadeOutStartTime=2.720000 MaxParticles=25 DetailMode=DM_High StartLocationRange=(X=(Min=-10.000000,Max=10.000000),Y=(Min=-10.000000,Max=10.000000),Z=(Min=-10.000000,Max=10.000000)) UseRotationFrom=PTRS_Actor SpinCCWorCW=(X=0.000000) SpinsPerSecondRange=(X=(Max=0.150000)) StartSpinRange=(X=(Min=-1.000000,Max=1.000000)) SizeScale(0)=(RelativeSize=2.200000) SizeScale(1)=(RelativeTime=0.500000,RelativeSize=3.200000) SizeScale(2)=(RelativeTime=1.000000,RelativeSize=4.000000) StartSizeRange=(X=(Min=1.000000,Max=20.000000),Y=(Min=1.000000,Max=20.000000),Z=(Min=1.000000,Max=20.000000)) InitialParticlesPerSecond=10000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'Effects_Tex.explosions.DSmoke_2' TextureUSubdivisions=1 TextureVSubdivisions=1 StartVelocityRange=(X=(Min=-350.000000,Max=350.000000),Y=(Min=-350.000000,Max=350.000000),Z=(Min=-5.000000,Max=50.000000)) VelocityLossRange=(X=(Min=3.000000,Max=3.000000),Y=(Min=3.000000,Max=3.000000)) End Object Emitters(9)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter14'
Begin Object Class=SpriteEmitter Name=SpriteEmitter15 UseCollision=True UseColorScale=True FadeOut=True FadeIn=True RespawnDeadParticles=False UniformSize=True AutomaticInitialSpawning=False UseRandomSubdivision=True Acceleration=(Z=-1000.000000) ExtentMultiplier=(X=0.000000,Y=0.000000,Z=0.000000) DampingFactorRange=(X=(Min=0.250000,Max=0.250000),Y=(Min=0.250000,Max=0.250000),Z=(Min=0.250000,Max=0.250000)) ColorScale(0)=(Color=(B=174,G=174,R=205,A=255)) ColorScale(1)=(RelativeTime=1.000000,Color=(B=174,G=174,R=205,A=255)) FadeOutStartTime=0.500000 MaxParticles=15 UseRotationFrom=PTRS_Actor StartSizeRange=(X=(Min=0.700000,Max=1.700000)) InitialParticlesPerSecond=10000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'Effects_Tex.BulletHits.snowchunksfinal' TextureUSubdivisions=2 TextureVSubdivisions=2 LifetimeRange=(Min=1.400000,Max=1.400000) StartVelocityRange=(X=(Min=-200.000000,Max=200.000000),Y=(Min=-200.000000,Max=200.000000),Z=(Min=-300.000000,Max=350.000000)) End Object Emitters(10)=SpriteEmitter'NicePack.NiceIceChunkEmitter.SpriteEmitter15'
AutoDestroy=True bNoDelete=False bNetTemporary=True RemoteRole=ROLE_SimulatedProxy LifeSpan=5.000000 TransientSoundVolume=150.000000 TransientSoundRadius=80.000000
}

View File

@ -0,0 +1,10 @@
// ScrN copy
class NiceNitroDecal extends ProjectedDecal;
#exec OBJ LOAD FILE=HTec_A.ukx
simulated function BeginPlay(){
if(!level.bDropDetail && FRand() < 0.4) projTexture = Texture'HTec_A.Nitro.NitroSplat';
super.BeginPlay();
}
defaultproperties
{ bClipStaticMesh=True CullDistance=7000.000000 LifeSpan=5.000000 DrawScale=0.500000
}

View File

@ -0,0 +1,6 @@
// ScrN copy
class NiceNitroGroundEffect extends NiceFreezeParticlesDirectional;
defaultproperties
{ Begin Object Class=SpriteEmitter Name=SpriteEmitter0 FadeOut=True FadeIn=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False ExtentMultiplier=(X=0.000000,Y=0.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)) Opacity=0.470000 FadeOutStartTime=0.940000 FadeInEndTime=0.300000 MaxParticles=50 StartLocationShape=PTLS_Polar SpinsPerSecondRange=(X=(Max=0.035000)) StartSpinRange=(X=(Min=-0.200000,Max=0.300000)) SizeScale(0)=(RelativeTime=0.500000,RelativeSize=0.900000) SizeScale(1)=(RelativeTime=1.000000,RelativeSize=0.500000) StartSizeRange=(X=(Min=15.000000,Max=35.000000),Y=(Min=15.000000,Max=35.000000),Z=(Min=15.000000,Max=35.000000)) InitialParticlesPerSecond=60.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'Effects_Tex.explosions.DSmoke_2' LifetimeRange=(Min=2.000000,Max=2.000000) StartVelocityRange=(X=(Min=-85.000000,Max=85.000000),Y=(Min=-85.000000,Max=85.000000)) StartVelocityRadialRange=(Min=-40.000000,Max=40.000000) End Object Emitters(0)=SpriteEmitter'NicePack.NiceNitroGroundEffect.SpriteEmitter0'
LifeSpan=5.000000
}

View File

@ -0,0 +1,190 @@
class NiceGUIBuyMenu extends UT2k4MainPage;
//The "Header"
var automated GUIImage HeaderBG_Left;
var automated GUIImage HeaderBG_Center;
var automated GUIImage HeaderBG_Right;
var automated GUILabel CurrentPerkLabel;
var automated GUILabel TimeLeftLabel;
var automated GUILabel WaveLabel;
var automated GUILabel HeaderBG_Left_Label;
var automated KFQuickPerkSelect QuickPerkSelect;
var automated KFBuyMenuFilter BuyMenuFilter;
var automated GUIButton StoreTabButton;
var automated GUIButton PerkTabButton;
//The "Footer"
var automated GUIImage WeightBG;
var automated GUIImage WeightIcon;
var automated GUIImage WeightIconBG;
var automated KFWeightBar WeightBar;
//const BUYLIST_CATS =7;
var() editconst noexport float SavedPitch;
var color RedColor;
var color GreenGreyColor;
var() UT2K4TabPanel ActivePanel;
var localized string CurrentPerk;
var localized string NoActivePerk;
var localized string TraderClose;
var localized string WaveString;
var localized string LvAbbrString;
function InitComponent(GUIController MyC, GUIComponent MyO)
{
local int i;
super.InitComponent(MyC, MyO);
c_Tabs.BackgroundImage = none;
c_Tabs.BackgroundStyle = none;
InitTabs();
for ( i = 0; i < c_Tabs.TabStack.Length; i++ )
{
c_Tabs.TabStack[i].bVisible = false;
}
UpdateWeightBar();
}
function InitTabs()
{
local int i;
for ( i = 0; i < PanelCaption.Length && i < PanelClass.Length && i < PanelHint.Length; i++ )
{
c_Tabs.AddTab(PanelCaption[i], PanelClass[i],, PanelHint[i]);
}
}
function UpdateWeightBar()
{
if ( KFHumanPawn(PlayerOwner().Pawn) != none )
{
WeightBar.MaxBoxes = KFHumanPawn(PlayerOwner().Pawn).MaxCarryWeight;
WeightBar.CurBoxes = KFHumanPawn(PlayerOwner().Pawn).CurrentWeight;
}
}
event Opened(GUIComponent Sender)
{
local rotator PlayerRot;
super.Opened(Sender);
c_Tabs.ActivateTabByName(PanelCaption[0], true);
// Tell the controller that he is on a shopping spree
if ( KFPlayerController(PlayerOwner()) != none )
{ KFPlayerController(PlayerOwner()).bShopping = true;
}
if ( KFWeapon(KFHumanPawn(PlayerOwner().Pawn).Weapon).bAimingRifle )
{
KFWeapon(KFHumanPawn(PlayerOwner().Pawn).Weapon).IronSightZoomOut();
}
// Set camera's pitch to zero when menu initialised (otherwise spinny weap goes kooky)
PlayerRot = PlayerOwner().Rotation;
SavedPitch = PlayerRot.Pitch;
PlayerRot.Yaw = PlayerRot.Yaw % 65536;
PlayerRot.Pitch = 0;
PlayerRot.Roll = 0;
PlayerOwner().SetRotation(PlayerRot);
SetTimer(0.05f, true);
}
function Timer()
{
UpdateHeader();
UpdateWeightBar();
}
function InternalOnClose(optional bool bCanceled)
{
local rotator NewRot;
// Reset player
NewRot = PlayerOwner().Rotation;
NewRot.Pitch = SavedPitch;
PlayerOwner().SetRotation(NewRot);
Super.OnClose(bCanceled);
}
function UpdateHeader()
{
local int TimeLeftMin, TimeLeftSec;
local string TimeString;
if ( KFPlayerController(PlayerOwner()) == none || PlayerOwner().PlayerReplicationInfo == none ||
PlayerOwner().GameReplicationInfo == none )
{
return;
}
// Current Perk
if ( KFPlayerController(PlayerOwner()).SelectedVeterancy != none )
{
CurrentPerkLabel.Caption = CurrentPerk$":" @ KFPlayerController(PlayerOwner()).SelectedVeterancy.default.VeterancyName @ LvAbbrString$KFPlayerReplicationInfo(PlayerOwner().PlayerReplicationInfo).ClientVeteranSkillLevel;
}
else
{
CurrentPerkLabel.Caption = CurrentPerk$":" @ NoActivePerk;
}
// Trader time left
TimeLeftMin = KFGameReplicationInfo(PlayerOwner().GameReplicationInfo).TimeToNextWave / 60;
TimeLeftSec = KFGameReplicationInfo(PlayerOwner().GameReplicationInfo).TimeToNextWave % 60;
if ( TimeLeftMin < 1 )
{
TimeString = "00:";
}
else
{
TimeString = "0" $ TimeLeftMin $ ":";
}
if ( TimeLeftSec >= 10 )
{
TimeString = TimeString $ TimeLeftSec;
}
else
{
TimeString = TimeString $ "0" $ TimeLeftSec;
}
TimeLeftLabel.Caption = TraderClose @ TimeString;
if ( KFGameReplicationInfo(PlayerOwner().GameReplicationInfo).TimeToNextWave < 10 )
{
TimeLeftLabel.TextColor = RedColor;
}
else
{
TimeLeftLabel.TextColor = GreenGreyColor;
}
// Wave Counter
WaveLabel.Caption = WaveString$":" @ (KFGameReplicationInfo(PlayerOwner().GameReplicationInfo).WaveNumber + 1)$"/"$KFGameReplicationInfo(PlayerOwner().GameReplicationInfo).FinalWave;
}
function KFBuyMenuClosed(optional bool bCanceled)
{
local rotator NewRot;
// Reset player
NewRot = PlayerOwner().Rotation;
NewRot.Pitch = SavedPitch;
PlayerOwner().SetRotation(NewRot);
Super.OnClose(bCanceled);
if ( KFPlayerController(PlayerOwner()) != none )
{ KFPlayerController(PlayerOwner()).bShopping = false;
}
}
function CloseSale(bool savePurchases)
{
Controller.CloseMenu(!savePurchases);
}
function bool ButtonClicked(GUIComponent Sender)
{
if ( Sender == PerkTabButton )
{
HandleParameters(PanelCaption[1], "OhHi!");
}
if ( Sender == StoreTabButton )
{
HandleParameters(PanelCaption[0], "OhHi!");
}
return true;
}
defaultproperties
{ Begin Object Class=GUIImage Name=HBGLeft Image=Texture'KF_InterfaceArt_tex.Menu.Thin_border' ImageStyle=ISTY_Stretched Hint="Perk Quick Select" WinTop=0.001000 WinLeft=0.001000 WinWidth=0.332300 WinHeight=0.100000 End Object HeaderBG_Left=GUIImage'NicePack.NiceGUIBuyMenu.HBGLeft'
Begin Object Class=GUIImage Name=HBGCenter Image=Texture'KF_InterfaceArt_tex.Menu.Thin_border' ImageStyle=ISTY_Stretched Hint="Trading Time Left" WinTop=0.001000 WinLeft=0.334000 WinWidth=0.331023 WinHeight=0.100000 End Object HeaderBG_Center=GUIImage'NicePack.NiceGUIBuyMenu.HBGCenter'
Begin Object Class=GUIImage Name=HBGRight Image=Texture'KF_InterfaceArt_tex.Menu.Thin_border' ImageStyle=ISTY_Stretched Hint="Current Perk" WinTop=0.001000 WinLeft=0.666000 WinWidth=0.332000 WinHeight=0.100000 End Object HeaderBG_Right=GUIImage'NicePack.NiceGUIBuyMenu.HBGRight'
Begin Object Class=GUILabel Name=Perk TextAlign=TXTA_Center TextColor=(B=158,G=176,R=175) WinTop=0.010000 WinLeft=0.665000 WinWidth=0.329761 WinHeight=0.050000 End Object CurrentPerkLabel=GUILabel'NicePack.NiceGUIBuyMenu.Perk'
Begin Object Class=GUILabel Name=Time Caption="Trader closes in 00:31" TextAlign=TXTA_Center TextColor=(B=158,G=176,R=175) TextFont="UT2LargeFont" WinTop=0.020952 WinLeft=0.335000 WinWidth=0.330000 WinHeight=0.035000 End Object TimeLeftLabel=GUILabel'NicePack.NiceGUIBuyMenu.Time'
Begin Object Class=GUILabel Name=Wave Caption="Wave: 7/10" TextAlign=TXTA_Center TextColor=(B=158,G=176,R=175) WinTop=0.052857 WinLeft=0.336529 WinWidth=0.327071 WinHeight=0.035000 End Object WaveLabel=GUILabel'NicePack.NiceGUIBuyMenu.Wave'
Begin Object Class=GUILabel Name=HBGLL Caption="Quick Perk Select" TextAlign=TXTA_Center TextColor=(B=158,G=176,R=175) TextFont="UT2ServerListFont" WinTop=0.007238 WinLeft=0.024937 WinWidth=0.329761 WinHeight=0.019524 End Object HeaderBG_Left_Label=GUILabel'NicePack.NiceGUIBuyMenu.HBGLL'
Begin Object Class=KFQuickPerkSelect Name=QS WinTop=0.011906 WinLeft=0.008008 WinWidth=0.316601 WinHeight=0.082460 OnDraw=QS.MyOnDraw End Object QuickPerkSelect=KFQuickPerkSelect'NicePack.NiceGUIBuyMenu.QS'
Begin Object Class=KFBuyMenuFilter Name=filter WinTop=0.051000 WinLeft=0.670000 WinWidth=0.305000 WinHeight=0.082460 OnDraw=filter.MyOnDraw End Object BuyMenuFilter=KFBuyMenuFilter'NicePack.NiceGUIBuyMenu.filter'
Begin Object Class=GUIButton Name=StoreTabB Caption="Store" FontScale=FNS_Small WinTop=0.072762 WinLeft=0.202801 WinWidth=0.050000 WinHeight=0.022000 OnClick=NiceGUIBuyMenu.ButtonClicked OnKeyEvent=StoreTabB.InternalOnKeyEvent End Object StoreTabButton=GUIButton'NicePack.NiceGUIBuyMenu.StoreTabB'
Begin Object Class=GUIButton Name=PerkTabB Caption="Perk" FontScale=FNS_Small WinTop=0.072762 WinLeft=0.127234 WinWidth=0.050000 WinHeight=0.022000 OnClick=NiceGUIBuyMenu.ButtonClicked OnKeyEvent=PerkTabB.InternalOnKeyEvent End Object PerkTabButton=GUIButton'NicePack.NiceGUIBuyMenu.PerkTabB'
Begin Object Class=GUIImage Name=Weight Image=Texture'KF_InterfaceArt_tex.Menu.Thin_border' ImageStyle=ISTY_Stretched WinTop=0.934206 WinLeft=0.001000 WinWidth=0.663086 WinHeight=0.065828 End Object WeightBG=GUIImage'NicePack.NiceGUIBuyMenu.Weight'
Begin Object Class=GUIImage Name=WeightIco Image=Texture'KillingFloorHUD.HUD.Hud_Weight' ImageStyle=ISTY_Scaled WinTop=0.946166 WinLeft=0.009961 WinWidth=0.033672 WinHeight=0.048992 RenderWeight=0.460000 End Object WeightIcon=GUIImage'NicePack.NiceGUIBuyMenu.WeightIco'
Begin Object Class=GUIImage Name=WeightIcoBG Image=Texture'KF_InterfaceArt_tex.Menu.Perk_box_unselected' ImageStyle=ISTY_Scaled WinTop=0.942416 WinLeft=0.006055 WinWidth=0.041484 WinHeight=0.054461 RenderWeight=0.450000 End Object WeightIconBG=GUIImage'NicePack.NiceGUIBuyMenu.WeightIcoBG'
Begin Object Class=KFWeightBar Name=WeightB WinTop=0.945302 WinLeft=0.055266 WinWidth=0.443888 WinHeight=0.053896 OnDraw=WeightB.MyOnDraw End Object WeightBar=KFWeightBar'NicePack.NiceGUIBuyMenu.WeightB'
RedColor=(R=255,A=255) GreenGreyColor=(B=158,G=176,R=175,A=255) CurrentPerk="Current Perk" NoActivePerk="No Active Perk!" TraderClose="Trader Closes in" WaveString="Wave" LvAbbrString="Lv" Begin Object Class=GUITabControl Name=PageTabs bDockPanels=True TabHeight=0.025000 BackgroundStyleName="TabBackground" WinTop=0.078000 WinLeft=0.005000 WinWidth=0.990000 WinHeight=0.025000 RenderWeight=0.490000 TabOrder=0 bAcceptsInput=True OnActivate=PageTabs.InternalOnActivate OnChange=NiceGUIBuyMenu.InternalOnChange End Object c_Tabs=GUITabControl'NicePack.NiceGUIBuyMenu.PageTabs'
Begin Object Class=BackgroundImage Name=PageBackground Image=Texture'Engine.WhiteSquareTexture' ImageColor=(B=20,G=20,R=20) ImageStyle=ISTY_Tiled RenderWeight=0.001000 End Object i_Background=BackgroundImage'NicePack.NiceGUIBuyMenu.PageBackground'
PanelClass(0)="KFGUI.KFTab_BuyMenu" PanelClass(1)="KFGUI.KFTab_Perks" PanelCaption(0)="Store" PanelCaption(1)="Perks" PanelHint(0)="Trade equipment and ammunition" PanelHint(1)="Select your current Perk" bAllowedAsLast=True OnClose=NiceGUIBuyMenu.KFBuyMenuClosed WhiteColor=(B=255,G=255,R=255)
}

View File

@ -0,0 +1,76 @@
class NiceGUIPerkButton extends GUIButton;
var bool isAltSkill;
var int skillPerkIndex, skillIndex;
var class<NiceSkill> associatedSkill;
function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
OnDraw = DrawSkillButton;
OnClick = SkillChange;
Super.InitComponent(MyController, MyOwner);
}
function bool SkillChange(GUIComponent Sender){
local byte newSkillChoice;
local NicePlayerController skillOwner;
if(isAltSkill) newSkillChoice = 1;
else newSkillChoice = 0;
skillOwner = NicePlayerController(PlayerOwner());
if(skillOwner != none){ skillOwner.ServerSetSkill(skillPerkIndex, skillIndex, newSkillChoice); skillOwner.SaveConfig();
}
return true;
}
function bool DrawSkillButton(Canvas cnvs){
// Variables that contain information about this button's skill
local NicePlayerController skillOwner;
local bool bAvailable, bSelected, bPending;
// Variables needed for text drawing
local int descLineOffset; // How much vertical space description took so far
local string skillEffects, line; // 'line' is next line from description to be drawn, 'skillEffects' is a not-yet drawn part of skill's effect description
local float textWidth, textHeight, nameHeight; // Variables for storing amount of space text uses
local int horizontalOffset, verticalOffset, smVerticalOffset; // Spaces between text and borders ('smVerticalOffset' is space between skill's name and description)
// Old values for font and it's scale
local Font oldFont;
local float oldFontScaleX, oldFontScaleY;
// Get skill parameters
skillOwner = NicePlayerController(PlayerOwner());
bAvailable = class'NiceVeterancyTypes'.static.CanUseSkill(skillOwner, associatedSkill);
if(bAvailable) bSelected = class'NiceVeterancyTypes'.static.HasSkill(skillOwner, associatedSkill);
bPending = class'NiceVeterancyTypes'.static.IsSkillPending(skillOwner, associatedSkill);
if(skillOwner == none || associatedSkill == none) return true;
// Text offset parameters that seem to give a good result
horizontalOffset = 10;
verticalOffset = 5;
smVerticalOffset = 2;
// Backup old font values and set the new ones
oldFont = cnvs.Font;
oldFontScaleX = cnvs.FontScaleX;
oldFontScaleY = cnvs.FontScaleY;
cnvs.Font = class'ROHUD'.Static.LoadSmallFontStatic(3);
cnvs.FontScaleX = 1.0;
cnvs.FontScaleY = 1.0;
// Draw text
// - Name
cnvs.SetPos(ActualLeft() + horizontalOffset, ActualTop() + verticalOffset);
if(!bAvailable) cnvs.SetDrawColor(0, 0, 0);
else if(bSelected) cnvs.SetDrawColor(255, 255, 255);
else cnvs.SetDrawColor(128, 128, 128);
cnvs.DrawText(associatedSkill.default.skillName);
cnvs.TextSize(associatedSkill.default.skillName, textWidth, nameHeight);
// - Description
cnvs.Font = class'ROHUD'.Static.LoadSmallFontStatic(5);
if(!bAvailable) cnvs.SetDrawColor(0, 0, 0);
else if(bSelected) cnvs.SetDrawColor(220, 220, 220);//180
else cnvs.SetDrawColor(140, 140, 140);//100
skillEffects = associatedSkill.default.skillEffects;
while(Len(skillEffects) > 0){ cnvs.WrapText(skillEffects, line, ActualWidth() - horizontalOffset * 2, cnvs.Font, cnvs.FontScaleX); cnvs.SetPos(ActualLeft() + horizontalOffset, ActualTop() + verticalOffset + nameHeight + smVerticalOffset + descLineOffset); cnvs.DrawText(line); cnvs.TextSize(line, textWidth, textHeight); descLineOffset += textHeight;
}
// Draw border
if(bAvailable && bSelected || bPending){ if(bAvailable && bSelected) cnvs.SetDrawColor(255, 255, 255); else cnvs.SetDrawColor(64, 64, 64); cnvs.SetPos(ActualLeft(), ActualTop()); cnvs.DrawLine(3, ActualWidth()); cnvs.DrawLine(1, ActualHeight()); cnvs.SetPos(ActualLeft() + ActualWidth() + 2, ActualTop() + ActualHeight()); cnvs.DrawLine(2, ActualWidth() + 2); cnvs.SetPos(ActualLeft() + ActualWidth(), ActualTop() + ActualHeight() + 2); cnvs.DrawLine(0, ActualHeight() + 2);
}
cnvs.Font = oldFont;
cnvs.FontScaleX = oldFontScaleX;
cnvs.FontScaleY = oldFontScaleY;
return true;
}
defaultproperties
{
}

View File

@ -0,0 +1,70 @@
class NiceGUISettings extends Settings_Tabs;
//var automated GUIButton skillButtonA;
var array<string> ForceProjItems;
var automated moCheckBox ch_WeapManagement;
var automated moCheckBox ch_AltSwitches;
var automated moCheckBox ch_DispCounters;
var automated moCheckBox ch_DisWeapProgress;
var automated moCheckBox ch_ShowHLMessages;
var automated moCheckBox ch_CancelFire;
var automated moCheckBox ch_CancelSwitching;
var automated moCheckBox ch_CancelNades;
var automated moCheckBox ch_CancelAiming;
var automated moCheckBox ch_ReloadWontWork;
var automated GUISectionBackground bg_WEAP;
var automated GUISectionBackground bg_RELOAD;
function InitComponent(GUIController MyController, GUIComponent MyOwner){
super.InitComponent(MyController, MyOwner);
}
function InternalOnLoadINI(GUIComponent sender, string s){
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(PlayerOwner());
if(nicePlayer == none) return;
switch(sender){
case ch_WeapManagement: ch_WeapManagement.Checked(nicePlayer.bNiceWeaponManagement); break;
case ch_AltSwitches: ch_AltSwitches.Checked(nicePlayer.bFlagAltSwitchesModes); break;
case ch_DispCounters: ch_DispCounters.Checked(nicePlayer.bFlagDisplayCounters); break;
case ch_DisWeapProgress: ch_DisWeapProgress.Checked(nicePlayer.bFlagDisplayWeaponProgress); break;
case ch_ShowHLMessages: ch_ShowHLMessages.Checked(nicePlayer.bFlagShowHLMessages); break;
case ch_CancelFire: ch_CancelFire.Checked(nicePlayer.bRelCancelByFire); break;
case ch_CancelSwitching: ch_CancelSwitching.Checked(nicePlayer.bRelCancelBySwitching); break;
case ch_CancelNades: ch_CancelNades.Checked(nicePlayer.bRelCancelByNades); break;
case ch_CancelAiming: ch_CancelAiming.Checked(nicePlayer.bRelCancelByAiming); break;
case ch_ReloadWontWork: ch_ReloadWontWork.Checked(nicePlayer.bFlagUseServerReload); break;
}
}
function InternalOnChange(GUIComponent Sender){
local NicePlayerController nicePlayer;
super.InternalOnChange(Sender);
nicePlayer = NicePlayerController(PlayerOwner());
if(nicePlayer == none) return;
switch(sender){
case ch_WeapManagement: nicePlayer.bNiceWeaponManagement = ch_WeapManagement.IsChecked(); break;
case ch_AltSwitches: nicePlayer.ServerSetAltSwitchesModes(ch_AltSwitches.IsChecked()); break;
case ch_DispCounters: nicePlayer.ServerSetDisplayCounters(ch_DispCounters.IsChecked()); break;
case ch_DisWeapProgress: nicePlayer.ServerSetDisplayWeaponProgress(ch_DisWeapProgress.IsChecked()); break;
case ch_ShowHLMessages: nicePlayer.ServerSetHLMessages(ch_ShowHLMessages.IsChecked()); break;
case ch_CancelFire: nicePlayer.bRelCancelByFire = ch_CancelFire.IsChecked(); break;
case ch_CancelSwitching: nicePlayer.bRelCancelBySwitching = ch_CancelSwitching.IsChecked(); break;
case ch_CancelNades: nicePlayer.bRelCancelByNades = ch_CancelNades.IsChecked(); break;
case ch_CancelAiming: nicePlayer.bRelCancelByAiming = ch_CancelAiming.IsChecked(); break;
case ch_ReloadWontWork: nicePlayer.ServerSetUseServerReload(ch_ReloadWontWork.IsChecked()); break;
}
nicePlayer.ClientSaveConfig();
}
// size = (x=0.0125, y=0.0) ; (w=1.0, h=0.865)
// tab order
defaultproperties
{ Begin Object Class=moCheckBox Name=WeaponManagement CaptionWidth=0.955000 Caption="Nice weapon management" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=WeaponManagement.InternalOnCreateComponent IniOption="@Internal" Hint="If checked, NicePack will use it's own system to manage weapon switching" WinTop=0.050000 WinLeft=0.012500 WinWidth=0.278000 TabOrder=4 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_WeapManagement=moCheckBox'NicePack.NiceGUISettings.WeaponManagement'
Begin Object Class=moCheckBox Name=AltSwitches CaptionWidth=0.955000 Caption="Alt fire switches modes" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=AltSwitches.InternalOnCreateComponent IniOption="@Internal" Hint="Assault-rifle only; if enabled - alt fire button switches between fire modes, otherwise - acts as an alt fire" WinTop=0.100000 WinLeft=0.012500 WinWidth=0.278000 TabOrder=6 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_AltSwitches=moCheckBox'NicePack.NiceGUISettings.AltSwitches'
Begin Object Class=moCheckBox Name=DispCounters CaptionWidth=0.955000 Caption="Display counters" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=DispCounters.InternalOnCreateComponent IniOption="@Internal" Hint="Toggles display of the various counters used by skills" WinTop=0.150000 WinLeft=0.012500 WinWidth=0.278000 TabOrder=7 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_DispCounters=moCheckBox'NicePack.NiceGUISettings.DispCounters'
Begin Object Class=moCheckBox Name=DispWeapProgress CaptionWidth=0.955000 Caption="Display weapon progress" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=DispWeapProgress.InternalOnCreateComponent IniOption="@Internal" Hint="Displays weapon progress rate, whoever it's defined by a skill that's using this functionality" WinTop=0.200000 WinLeft=0.012500 WinWidth=0.278000 TabOrder=8 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_DisWeapProgress=moCheckBox'NicePack.NiceGUISettings.DispWeapProgress'
Begin Object Class=moCheckBox Name=ShowHLMessages CaptionWidth=0.955000 Caption="Show Hardcore Level messages" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=ShowHLMessages.InternalOnCreateComponent IniOption="@Internal" Hint="Enable to be notified each time Hardcore Level is changed" WinTop=0.300000 WinLeft=0.012500 WinWidth=0.278000 TabOrder=9 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_ShowHLMessages=moCheckBox'NicePack.NiceGUISettings.ShowHLMessages'
Begin Object Class=moCheckBox Name=CancelFire CaptionWidth=0.955000 Caption="Cancel reload by shooting" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=CancelFire.InternalOnCreateComponent IniOption="@Internal" Hint="If checked, you'll be able to cancel reload of converted weapons by shooting (when you have ammo)" WinTop=0.050000 WinLeft=0.517500 WinWidth=0.287000 TabOrder=11 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_CancelFire=moCheckBox'NicePack.NiceGUISettings.CancelFire'
Begin Object Class=moCheckBox Name=CancelSwitching CaptionWidth=0.955000 Caption="Cancel reload by switching weapons" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=CancelSwitching.InternalOnCreateComponent IniOption="@Internal" Hint="If checked, you'll be able to cancel reload of converted weapons by switching to different weapon" WinTop=0.100000 WinLeft=0.517500 WinWidth=0.287000 TabOrder=12 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_CancelSwitching=moCheckBox'NicePack.NiceGUISettings.CancelSwitching'
Begin Object Class=moCheckBox Name=CancelNades CaptionWidth=0.955000 Caption="Cancel reload by throwing grenades" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=CancelNades.InternalOnCreateComponent IniOption="@Internal" Hint="If checked, you'll be able to cancel reload of converted weapons by throwing a grenade" WinTop=0.150000 WinLeft=0.517500 WinWidth=0.287000 TabOrder=13 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_CancelNades=moCheckBox'NicePack.NiceGUISettings.CancelNades'
Begin Object Class=moCheckBox Name=CancelAiming CaptionWidth=0.955000 Caption="Cancel reload by aiming" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=CancelAiming.InternalOnCreateComponent IniOption="@Internal" Hint="If checked, you'll be able to cancel reload of converted weapons by going into iron sights (when you have ammo)" WinTop=0.200000 WinLeft=0.517500 WinWidth=0.287000 TabOrder=14 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_CancelAiming=moCheckBox'NicePack.NiceGUISettings.CancelAiming'
Begin Object Class=moCheckBox Name=ServerReload CaptionWidth=0.955000 Caption="My reload doesn't work" ComponentClassName="ScrnBalanceSrv.ScrnGUICheckBoxButton" OnCreateComponent=ServerReload.InternalOnCreateComponent IniOption="@Internal" Hint="Check this option ONLY in case converted weapons don't reload at all for you; this option should fix the problem, but then latency will affect both reload and active reload" WinTop=0.250000 WinLeft=0.517500 WinWidth=0.287000 TabOrder=15 OnChange=NiceGUISettings.InternalOnChange OnLoadINI=NiceGUISettings.InternalOnLoadINI End Object ch_ReloadWontWork=moCheckBox'NicePack.NiceGUISettings.ServerReload'
Begin Object Class=GUISectionBackground Name=WEAPBG Caption="General weapon settings" WinTop=0.012500 WinWidth=0.495000 WinHeight=0.287500 RenderWeight=0.100100 OnPreDraw=WeaponsBG.InternalPreDraw End Object bg_WEAP=GUISectionBackground'NicePack.NiceGUISettings.WEAPBG'
Begin Object Class=GUISectionBackground Name=RELOADBG Caption="Weapon reload settings" WinTop=0.012500 WinLeft=0.505000 WinWidth=0.495000 WinHeight=0.287500 RenderWeight=0.100100 OnPreDraw=WeaponsBG.InternalPreDraw End Object bg_RELOAD=GUISectionBackground'NicePack.NiceGUISettings.RELOADBG'
}

View File

@ -0,0 +1,216 @@
class NiceInteraction extends Interaction
dependson(NicePack)
dependson(NiceAbilityManager);
#exec OBJ LOAD FILE=KillingFloor2HUD.utx
var NicePack NicePackMutator;
var Material bleedIcon, poisonIcon;
var Texture greenBar, redBar;
var Texture shield;
var float size;
// Weapon box sizes
var float InventoryBoxWidth;
var float InventoryBoxHeight;
var float BorderSize;
event NotifyLevelChange(){
Master.RemoveInteraction(self);
}
function RegisterMutator(NicePack activePack){
NicePackMutator = activePack;
}
function bool isPoisoned(ScrnHumanPawn pwn){
local Inventory I;
if(pwn.Inventory != none) for(I = pwn.Inventory; I != none; I = I.Inventory) if(I != none && MeanPoisonInventory(I) != none) return true;
return false;
}
function PostRender(Canvas C){
local int i;
local NicePack niceMutator;
local NiceHumanPawn nicePawn;
local class<NiceVeterancyTypes> niceVet;
local MeanReplicationInfo szRI;
local NiceWeapon niceWeap;
local NicePlayerController nicePlayer;
local ScrnHUD scrnHUDInstance;
local Texture barTexture;
local int x, y, center, barWidth, offset;
local int missesWidth, missesHeight, missesSpace;
local int missesX, missesY;
if(C == none) return;
if(C.ViewPort == none) return;
if(C.ViewPort.Actor == none) return;
if(C.ViewPort.Actor.Pawn == none) return;
nicePlayer = NicePlayerController(C.ViewPort.Actor.Pawn.Controller);
niceWeap = NiceWeapon(C.ViewPort.Actor.Pawn.Weapon);
if(nicePlayer == none) return;
scrnHUDInstance = ScrnHUD(nicePlayer.myHUD);
//// Draw bleed and poison icons
C.SetDrawColor(255, 255, 255);
szRI = class'MeanReplicationInfo'.static.findSZri(ViewportOwner.Actor.PlayerReplicationInfo);
offset = 4;
if(szRI != none){ if(szRI.isBleeding){ x = C.ClipX * 0.007; y = C.ClipY * 0.93 - size * offset; C.SetPos(x, y); C.DrawTile(bleedIcon, size, size, 0, 0, bleedIcon.MaterialUSize(), bleedIcon.MaterialVSize()); } offset++; if(isPoisoned(ScrnHumanPawn(C.ViewPort.Actor.Pawn))){ x = C.ClipX * 0.007; y = C.ClipY * 0.93 - size * offset; C.SetPos(x, y); C.DrawTile(poisonIcon, size, size, 0, 0, poisonIcon.MaterialUSize(), poisonIcon.MaterialVSize()); }
}
if(niceWeap != none && niceWeap.bShowSecondaryCharge && scrnHUDInstance != none){ C.ColorModulate.X = 1; C.ColorModulate.Y = 1; C.ColorModulate.Z = 1; C.ColorModulate.W = scrnHUDInstance.HudOpacity / 255; if(!scrnHUDInstance.bLightHud) scrnHUDInstance.DrawSpriteWidget(C, scrnHUDInstance.SecondaryClipsBG); scrnHUDInstance.DrawSpriteWidget(C, scrnHUDInstance.SecondaryClipsIcon); scrnHUDInstance.SecondaryClipsDigits.value = niceWeap.secondaryCharge; scrnHUDInstance.DrawNumericWidget(C, scrnHUDInstance.SecondaryClipsDigits, scrnHUDInstance.DigitsSmall);
}
niceMutator = class'NicePack'.static.Myself(C.ViewPort.Actor.Pawn.Level);
if(niceMutator == none) return;
//// Draw counters
if(nicePlayer != none && nicePlayer.bFlagDisplayCounters){ x = C.ClipX * 0.5 - (64 + 2) * niceMutator.GetVisibleCountersAmount(); y = C.ClipY * 0.01; for(i = 0;i < niceMutator.niceCounterSet.Length;i ++) if(niceMutator.niceCounterSet[i].value != 0 || niceMutator.niceCounterSet[i].bShowZeroValue){ DrawCounter(C, niceMutator.niceCounterSet[i], x, y, C.ViewPort.Actor.Pawn.PlayerReplicationInfo.Team); x += 128 + 4; }
}
//// Draw weapons progress bars
if(nicePlayer != none && nicePlayer.bFlagDisplayWeaponProgress){ x = C.ClipX - InventoryBoxWidth * C.ClipX - 5; y = C.ClipY * 0.5 - 0.5 * (InventoryBoxHeight * C.ClipX + 4) * niceMutator.niceWeapProgressSet.Length; for(i = 0;i < niceMutator.niceWeapProgressSet.Length;i ++){ DrawWeaponProgress(C, niceMutator.niceWeapProgressSet[i], x, y, C.ViewPort.Actor.Pawn.PlayerReplicationInfo.Team); y += (InventoryBoxHeight * C.ClipX + 4); }
}
//// Draw invincibility bar
nicePawn = NiceHumanPawn(nicePlayer.pawn);
if(nicePawn != none && nicePawn.invincibilityTimer != 0.0){ C.SetDrawColor(255, 255, 255); if(nicePawn.invincibilityTimer > 0) barTexture = greenBar; else barTexture = redBar; center = C.ClipX * 0.5; y = C.ClipY * 0.75; barWidth = C.ClipX * 0.2; niceVet = class'NiceVeterancyTypes'.static. GetVeterancy(nicePawn.PlayerReplicationInfo); if(niceVet != none){ if(nicePawn.invincibilityTimer > 0){ barWidth *= nicePawn.invincibilityTimer / niceVet.static.GetInvincibilityDuration(nicePawn.KFPRI); } else{ barWidth *= nicePawn.invincibilityTimer / class'NiceSkillZerkGunzerker'.default.cooldown; } } else barWidth = 0; x = center - (barWidth / 2); C.SetPos(x, y); C.DrawTile(barTexture, barWidth, 32, 0, 0, barTexture.MaterialUSize(), barTexture.MaterialVSize()); if(nicePawn.safeMeleeMisses <= 0) return; missesSpace = 10;//64x64 => 16x16 missesHeight = 16; missesWidth = nicePawn.safeMeleeMisses * 16 + (nicePawn.safeMeleeMisses - 1) * missesSpace; missesX = center - (missesWidth / 2); missesY = y + (32 - missesHeight) * 0.5; for(i = 0;i < nicePawn.safeMeleeMisses;i ++){ C.SetPos(missesX + i * (16 + missesSpace), missesY); C.DrawTile(shield, 16, 16, 0, 0, shield.MaterialUSize(), shield.MaterialVSize()); }
}
// Draw cooldowns
if(nicePlayer.abilityManager == none) return;
for(i = 0;i < nicePlayer.abilityManager.currentAbilitiesAmount;i ++) DrawAbilityCooldown(C, i);
}
function DrawCounter(Canvas C, NicePack.CounterDisplay counter, int x, int y, TeamInfo team){
local float borderSpace;
local Texture textureToDraw;
local float textWidth, textHeight;
local string textToDraw;
// Some per-defined values for drawing
local int iconSize, backgroundWidth, backgroundHeight;
// Fill some constants that will dictate how to display counter
iconSize = 64;
backgroundWidth = 128;
backgroundHeight = 64;
borderSpace = 8;
// Reset color
if(team.teamIndex == 0) C.SetDrawColor(255, 64, 64);
else C.SetDrawColor(team.teamColor.R, team.teamColor.G, team.teamColor.B);
// Draw background
C.SetPos(x, y);
textureToDraw = Texture(class'HUDKillingFloor'.default.HealthBG.WidgetTexture);
C.DrawTile(textureToDraw, 128, 64, 0, 0, textureToDraw.MaterialUSize(), textureToDraw.MaterialVSize());
// Draw appropriate icon
C.SetPos(x + borderSpace, y + borderSpace);
textureToDraw = counter.icon;
C.DrawTile(textureToDraw, 64 - 2*borderSpace, 64 - 2 * borderSpace, 0, 0, textureToDraw.MaterialUSize(), textureToDraw.MaterialVSize());
// Draw numbers
textToDraw = string(counter.value);
C.Font = class'ROHUD'.Static.LoadSmallFontStatic(1);
C.TextSize(textToDraw, textWidth, textHeight);
C.SetPos(x + iconSize + (backgroundWidth - iconSize - textWidth) / 2, y + (backgroundHeight - textHeight) / 2 + 2);
C.DrawText(textToDraw);
}
function DrawAbilityCooldown(Canvas C, int abilityIndex){
local Texture skillTexture, backgroundTexture;
local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer;
local class<NiceVeterancyTypes> niceVet;
local int x, y;
local string textToDraw;
local float textWidth, textHeight;
local NiceAbilityManager.EAbilityState abilityState;
if(C == none) return;
if(C.ViewPort == none) return;
if(C.ViewPort.Actor == none) return;
nicePawn = NiceHumanPawn(C.ViewPort.Actor.Pawn);
nicePlayer = NicePlayerController(C.ViewPort.Actor.Pawn.Controller);
if(nicePawn == none) return;
if(nicePlayer == none || nicePlayer.abilityManager == none) return;
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePawn.KFPRI);
skillTexture = nicePlayer.abilityManager.currentAbilities[abilityIndex]. description.icon;
if(skillTexture == none) return;
// Set stuff up
x = C.ClipX * 0.265;
x += abilityIndex * (10 + 64);
y = C.ClipY * 0.93;
textToDraw = string(int(Ceil(nicePlayer.abilityManager.currentAbilities[abilityIndex].cooldown)));
backgroundTexture = Texture'KillingFloorHUD.HUD.Hud_Box_128x64';
// Reset color
C.SetDrawColor(255, 64, 64);
// Draw background
C.SetPos(x, y);
C.DrawTile(backgroundTexture, 64, 64, 0, 0, backgroundTexture.MaterialUSize(), backgroundTexture.MaterialVSize());
C.SetPos(x, y);
C.DrawTile(skillTexture, 64, 64, 0, 0, skillTexture.MaterialUSize(), skillTexture.MaterialVSize());
// Draw additional background
abilityState = nicePlayer.abilityManager.currentAbilities[abilityIndex].myState;
if(abilityState == ASTATE_ACTIVE) C.SetDrawColor(255, 0, 0, 128);
if(abilityState == ASTATE_COOLDOWN) C.SetDrawColor(0, 0, 0, 192);
if(abilityState != ASTATE_READY){ C.SetPos(x, y); C.DrawTileStretched(Material'KillingFloorHUD.HUD.WhiteTexture', 64, 64);
}
// Draw cooldown stuff
if(abilityState == ASTATE_COOLDOWN){ C.SetDrawColor(255, 192, 192); C.Font = class'ROHUD'.static.LoadSmallFontStatic(1); C.TextSize(textToDraw, textWidth, textHeight); C.SetPos(x, y); C.SetPos(x + (64 - textWidth) / 2, y + (64 - textHeight) / 2 + 2); C.DrawText(textToDraw);
}
// Draw calibration GUI
DrawCalibrationStars(C);
}
function DrawCalibrationStars(Canvas C){
local Texture starTexture;
local int x, y, i;
local int starsAmount;
local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer;
if(C == none) return;
if(C.ViewPort == none) return;
if(C.ViewPort.Actor == none) return;
nicePawn = NiceHumanPawn(C.ViewPort.Actor.Pawn);
if(nicePawn == none) return;
if(nicePawn.currentCalibrationState == CALSTATE_NOABILITY) return;
nicePlayer = NicePlayerController(nicePawn.controller);
if(nicePlayer == none) return;
starsAmount = nicePawn.calibrationScore;
x = C.ClipX * 0.5;
x -= 0.5 * (starsAmount * 32 + (starsAmount - 1) * 16);
if(nicePawn.currentCalibrationState == CALSTATE_ACTIVE) y = C.ClipY * 0.6;
else y = C.ClipY * 0.02;
starTexture = Texture'KillingFloorHUD.HUD.Hud_Perk_Star';
for(i = 0;i < starsAmount;i ++){ C.SetPos(x, y); C.SetDrawColor(255, 255, 255); C.DrawTile(starTexture, 32, 32, 0, 0, starTexture.MaterialUSize(), starTexture.MaterialVSize()); x += 32 + 16;
}
}
function DrawWeaponProgress(Canvas C, NicePack.WeaponProgressDisplay weapProgress, int x, int y, TeamInfo team){
local float textWidth, textHeight;
local string textToDraw;
local float TempWidth, TempHeight, TempBorder;
TempWidth = InventoryBoxWidth * C.ClipX;
TempHeight = InventoryBoxHeight * C.ClipX;
TempBorder = BorderSize * C.ClipX;
// Draw background bar
if(team.teamIndex == 0) C.SetDrawColor(255, 64, 64, 64);
else C.SetDrawColor(team.teamColor.R, team.teamColor.G, team.teamColor.B, 64);
C.SetPos(x, y);
C.DrawTile(Texture'Engine.WhiteSquareTexture', TempWidth * weapProgress.progress, TempHeight, 0, 0, 2, 2);
// Draw this item's Background
if(team.teamIndex == 0) C.SetDrawColor(255, 64, 64);
else C.SetDrawColor(team.teamColor.R, team.teamColor.G, team.teamColor.B);
C.SetPos(x, y);
C.DrawTileStretched(Texture'KillingFloorHUD.HUD.HUD_Rectangel_W_Stroke', TempWidth, TempHeight);
// Draw the Weapon's Icon over the Background
C.SetDrawColor(255, 255, 255);
C.SetPos(x + TempBorder, y + TempBorder);
if(weapProgress.weapClass.default.HudImage != none) C.DrawTile(weapProgress.weapClass.default.HudImage, TempWidth - (2.0 * TempBorder), TempHeight - (2.0 * TempBorder), 0, 0, 256, 192);
// Draw counter, if needed
if(team.teamIndex == 0) C.SetDrawColor(255, 64, 64);
else C.SetDrawColor(team.teamColor.R, team.teamColor.G, team.teamColor.B);
if(weapProgress.bShowCounter){ textToDraw = string(weapProgress.counter); C.Font = class'ROHUD'.Static.LoadSmallFontStatic(5); C.TextSize(textToDraw, textWidth, textHeight); C.SetPos(x + TempWidth - TempBorder - textWidth, y + TempHeight - TempBorder - textHeight + 2); C.DrawText(textToDraw);
}
}
function bool KeyEvent(EInputKey Key, EInputAction Action, float Delta){
local bool bNeedsReload;
local string Alias, LeftPart, RigthPart;
local NiceWeapon niceWeap;
local NicePlayerController nicePlayer;
// Find controller and current weapon
nicePlayer = NicePlayerController(ViewportOwner.Actor);
if(nicePlayer == none) return false;
if(nicePlayer.Pawn != none) niceWeap = NiceWeapon(nicePlayer.Pawn.Weapon);
// If this is a button press - detect alias
if(Action == IST_Press){ // Check for reload command Alias = nicePlayer.ConsoleCommand("KEYBINDING" @ nicePlayer.ConsoleCommand("KEYNAME" @ Key)); if(nicePlayer.bAdvReloadCheck) bNeedsReload = InStr(Caps(Alias), "RELOADMENOW") > -1 || InStr(Caps(Alias), "RELOADWEAPON") > -1; if(Divide(Alias, " ", LeftPart, RigthPart)) Alias = LeftPart; if(Key == IK_MouseWheelUp || Key == IK_MouseWheelDown){ nicePlayer.UpdateSelectors(); if(nicePlayer.hasZeroSelector && nicePlayer.bUsesMouseWheel && nicePlayer.bNiceWeaponManagement){ nicePlayer.ScrollSelector(0, nicePlayer.bMouseWheelLoops, Key == IK_MouseWheelUp); return true; } }
}
// Open trader on movement
if(Alias ~= "MoveForward" || Alias ~= "MoveBackward" || Alias ~= "TurnLeft" || Alias ~= "TurnRight" || Alias ~= "StrafeLeft" || Alias ~= "StrafeRight" || Alias ~= "Axis"){
// Open trader if it's a pre-game if(NicePackMutator.bIsPreGame && NicePackMutator.bInitialTrader && (NicePackMutator.bStillDuringInitTrader || !nicePlayer.bOpenedInitTrader) && nicePlayer.Pawn != none){ nicePlayer.ShowBuyMenu("Initial trader", KFHumanPawn(nicePlayer.Pawn).MaxCarryWeight); nicePlayer.bOpenedInitTrader = true; return true; } //nicePlayer.ClientOpenMenu("NicePack.NiceGUIBuyMenu",,"Test stuff",string(15));
}
// Reload if we've detected a reload alias in this button's command
if(niceWeap != none && !nicePlayer.bUseServerReload && (bNeedsReload || Alias ~= "ReloadMeNow" || Alias ~= "ReloadWeapon")) niceWeap.ClientReloadMeNow();
return false;
}
defaultproperties
{ bleedIcon=Texture'NicePackT.MeanZeds.bleedIcon' poisonIcon=Texture'NicePackT.MeanZeds.poisonIcon' greenBar=Texture'KFStoryGame_Tex.HUD.Batter_Fill' redBar=Texture'KFStoryGame_Tex.HUD.BarFill_Red' Shield=Texture'KillingFloorHUD.HUD.Hud_Shield' Size=75.599998 InventoryBoxWidth=0.100000 InventoryBoxHeight=0.075000 BorderSize=0.005000 bVisible=True
}

View File

@ -0,0 +1,54 @@
class NiceInvasionLoginMenu extends ScrnInvasionLoginMenu;
var bool bShowScrnMenu;
// copy-pasted from ScrnInvasionLoginMenu to change change remove news tab and add skills tab
function InitComponent(GUIController MyController, GUIComponent MyOwner){
local int i;
local string s;
local eFontScale FS;
local SRMenuAddition M;
local int indexAfterScrn;
// Setup panel classes.
Panels[0].ClassName = string(Class'ScrnBalanceSrv.ScrnTab_MidGamePerks');
Panels[1].ClassName = string(Class'NicePack.NicePanelSkills');
Panels[2].ClassName = string(Class'SRTab_MidGameVoiceChat');
Panels[3].ClassName = string(Class'SRTab_MidGameStats');
Panels[0].Caption = Class'KFInvasionLoginMenu'.Default.Panels[1].Caption;
Panels[1].Caption = "Skills";
Panels[2].Caption = Class'KFInvasionLoginMenu'.Default.Panels[2].Caption;
Panels[0].Hint = Class'KFInvasionLoginMenu'.Default.Panels[1].Hint;
Panels[1].Hint = "Customize your perk";
Panels[2].Hint = Class'KFInvasionLoginMenu'.Default.Panels[2].Hint;
b_Spec.Caption=class'KFTab_MidGamePerks'.default.b_Spec.Caption;
b_MatchSetup.Caption=class'KFTab_MidGamePerks'.default.b_MatchSetup.Caption;
b_KickVote.Caption=class'KFTab_MidGamePerks'.default.b_KickVote.Caption;
b_MapVote.Caption=class'KFTab_MidGamePerks'.default.b_MapVote.Caption;
b_Quit.Caption=class'KFTab_MidGamePerks'.default.b_Quit.Caption;
b_Favs.Caption=class'KFTab_MidGamePerks'.default.b_Favs.Caption;
b_Favs.Hint=class'KFTab_MidGamePerks'.default.b_Favs.Hint;
b_Settings.Caption=class'KFTab_MidGamePerks'.default.b_Settings.Caption;
b_Browser.Caption=class'KFTab_MidGamePerks'.default.b_Browser.Caption;
// Other panels
Panels[4].ClassName = "ScrnBalanceSrv.ScrnTab_Achievements";
Panels[4].Caption = "Achievements";
Panels[4].Hint = "ScrN server-side achievements";
if(default.bShowScrnMenu){ Panels[5].ClassName = "ScrnBalanceSrv.ScrnTab_UserSettings"; Panels[5].Caption = "ScrN Features"; Panels[5].Hint = "ScrN Balance features, settings and info"; indexAfterScrn = 6;
}
else indexAfterScrn = 5;
Panels[indexAfterScrn].ClassName = "NicePack.NiceGUISettings";
Panels[indexAfterScrn].Caption = "Nice settings";
Panels[indexAfterScrn].Hint = "Settings specific to NicePack mutator";
Panels.Length = indexAfterScrn + 1;
Super(UT2K4PlayerLoginMenu).InitComponent(MyController, MyOwner);
// Mod menus
foreach MyController.ViewportOwner.Actor.DynamicActors(class'SRMenuAddition',M) if( M.bHasInit ) { AddOnList[AddOnList.Length] = M; M.NotifyMenuOpen(Self,MyController); }
s = GetSizingCaption();
for ( i = 0; i < Controls.Length; i++ )
{ if (GUIButton(Controls[i]) != none) { GUIButton(Controls[i]).bAutoSize = true; GUIButton(Controls[i]).SizingCaption = s; GUIButton(Controls[i]).AutoSizePadding.HorzPerc = 0.04; GUIButton(Controls[i]).AutoSizePadding.VertPerc = 0.5; }
}
s = class'KFTab_MidGamePerks'.default.PlayerStyleName;
PlayerStyle = MyController.GetStyle(s, fs);
InitGRI();
}
defaultproperties
{
}

View File

@ -0,0 +1,14 @@
class NiceLobbyFooter extends ScrnLobbyFooter;
function bool OnFooterClick(GUIComponent Sender)
{
if (Sender == b_Perks){ PlayerOwner().ClientOpenMenu(string(Class'NicePack.NiceInvasionLoginMenu'), false); return false;
}
else if(Sender == b_ViewMap){ if(KF_StoryGRI(PlayerOwner().Level.GRI) == none){ LobbyMenu(PageOwner).bAllowClose = true; PlayerOwner().ClientCloseMenu(true, false); LobbyMenu(PageOwner).bAllowClose = false; }
}
else if(Sender == b_Ready){ return super(LobbyFooter).OnFooterClick(Sender); // bypass serverperks
}
else return super.OnFooterClick(Sender);
}
defaultproperties
{
}

View File

@ -0,0 +1,4 @@
class NiceLobbyMenu extends ScrnLobbyMenu;
defaultproperties
{ Begin Object Class=NiceLobbyFooter Name=BuyFooter RenderWeight=0.300000 TabOrder=8 bBoundToParent=False bScaleToParent=False OnPreDraw=BuyFooter.InternalOnPreDraw End Object t_Footer=NiceLobbyFooter'NicePack.NiceLobbyMenu.BuyFooter'
}

View File

@ -0,0 +1,26 @@
class NicePanelSkills extends Settings_Tabs;
var automated NiceGUIPerkButton skillButtonA[5], skillButtonB[5];
function ShowPanel(bool bShow){
local int i;
local class<NiceVeterancyTypes> niceVet;
local NicePlayerController nicePlayer;
Super.ShowPanel(bShow);
nicePlayer = NicePlayerController(PlayerOwner());
if(nicePlayer != none) niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePlayer.PlayerReplicationInfo);
if(niceVet != none){ for(i = 0;i < 5;i ++){ skillButtonA[i].skillIndex = i; skillButtonB[i].skillIndex = i; skillButtonA[i].skillPerkIndex = niceVet.default.PerkIndex; skillButtonB[i].skillPerkIndex = niceVet.default.PerkIndex; skillButtonA[i].isAltSkill = false; skillButtonB[i].isAltSkill = true; skillButtonA[i].associatedSkill = niceVet.default.SkillGroupA[i]; skillButtonB[i].associatedSkill = niceVet.default.SkillGroupB[i]; }
}
}
// size = (x=0.0125, y=0.0) ; (w=1.0, h=0.865)
// setup caption
defaultproperties
{ Begin Object Class=NiceGUIPerkButton Name=btn1A WinTop=0.012500 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=1 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn1A.InternalOnKeyEvent End Object skillButtonA(0)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn1A'
Begin Object Class=NiceGUIPerkButton Name=btn2A WinTop=0.188500 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=3 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn2A.InternalOnKeyEvent End Object skillButtonA(1)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn2A'
Begin Object Class=NiceGUIPerkButton Name=btn3A WinTop=0.364500 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=5 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn3A.InternalOnKeyEvent End Object skillButtonA(2)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn3A'
Begin Object Class=NiceGUIPerkButton Name=btn4A WinTop=0.540500 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=7 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn4A.InternalOnKeyEvent End Object skillButtonA(3)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn4A'
Begin Object Class=NiceGUIPerkButton Name=btn5A WinTop=0.716500 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=9 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn5A.InternalOnKeyEvent End Object skillButtonA(4)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn5A'
Begin Object Class=NiceGUIPerkButton Name=btn1B WinTop=0.012500 WinLeft=0.505000 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=2 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn1B.InternalOnKeyEvent End Object skillButtonB(0)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn1B'
Begin Object Class=NiceGUIPerkButton Name=btn2B WinTop=0.188500 WinLeft=0.505000 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=4 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn2B.InternalOnKeyEvent End Object skillButtonB(1)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn2B'
Begin Object Class=NiceGUIPerkButton Name=btn3B WinTop=0.364500 WinLeft=0.505000 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=6 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn3B.InternalOnKeyEvent End Object skillButtonB(2)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn3B'
Begin Object Class=NiceGUIPerkButton Name=btn4B WinTop=0.540500 WinLeft=0.505000 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=8 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn4B.InternalOnKeyEvent End Object skillButtonB(3)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn4B'
Begin Object Class=NiceGUIPerkButton Name=btn5B WinTop=0.716500 WinLeft=0.505000 WinWidth=0.495000 WinHeight=0.160000 RenderWeight=2.000000 TabOrder=10 bBoundToParent=True bScaleToParent=True bMouseOverSound=False OnClickSound=CS_None OnKeyEvent=btn5B.InternalOnKeyEvent End Object skillButtonB(4)=NiceGUIPerkButton'NicePack.NicePanelSkills.btn5B'
}

53
sources/NiceFFVoting.uc Normal file
View File

@ -0,0 +1,53 @@
class NiceFFVoting extends ScrnVotingOptions;
var NicePack Mut;
const VOTE_CHANGE = 1;
const VOTE_RESET = 2;
function int GetGroupVoteIndex(PlayerController Sender, string Group, string Key, out string Value, out string VoteInfo){
local TeamGame TG;
local float ffScale;
local bool bCanIncrease;
ffScale = float(Value);
TG = TeamGame(Level.Game);
bCanIncrease = true;
if(Mut != none){
bCanIncrease = !Mut.bFFWasIncreased || !Mut.bOneFFIncOnly;
if(Mut.ScrnGT != none)
bCanIncrease = bCanIncrease && (!Mut.bNoLateFFIncrease || (Mut.ScrnGT.WaveNum < 1 || (Mut.ScrnGT.WaveNum == 2 && Mut.ScrnGT.bTradingDoorsOpen)));
}
if(Key ~= "CHANGE"){
if(ffScale < 0.0 || ffScale > 1.0)
return VOTE_ILLEGAL;
if(TG != none && (ffScale <= TG.FriendlyFireScale || bCanIncrease))
return VOTE_CHANGE;
else
return VOTE_ILLEGAL;
}
else if(Key ~= "RESET")
return VOTE_RESET;
return VOTE_UNKNOWN;
}
function ApplyVoteValue(int VoteIndex, string VoteValue){
local TeamGame TG;
local float ffScale;
TG = TeamGame(Level.Game);
if(VoteIndex == VOTE_CHANGE){
ffScale = float(VoteValue);
ffScale = FMax(0.0, FMin(1.0, ffScale));
}
else if(VoteIndex == VOTE_RESET)
ffScale = TG.default.FriendlyFireScale;
if(TG != none){
if(ffScale > TG.FriendlyFireScale)
Mut.bFFWasIncreased = true;
TG.FriendlyFireScale = ffScale;
}
}
function SendGroupHelp(PlayerController Sender, string Group){
super.SendGroupHelp(Sender, Group);
}
defaultproperties
{
DefaultGroup="FF"
HelpInfo(0)="%pFF %gRESET%w|%rCHANGE %y<ff_scale> %wChanges friendly fire scale."
GroupInfo(0)="%pFF %gRESET%w|%rCHANGE %y<ff_scale> %wChanges friendly fire scale."
}

74
sources/NiceGameType.uc Normal file
View File

@ -0,0 +1,74 @@
// made to fix KFStoryGameInfo loading for KFO maps
class NiceGameType extends ScrnGameType;
var NicePack NicePackMutator;
function RegisterMutator(NicePack activePack){
NicePackMutator = activePack;
}
function OverrideMonsterHealth(KFMonster M){}
/*event InitGame(string Options, out string Error){
local int i, j;
if(ScrnGameLength == none) ScrnGameLength = new(none, string(KFGameLength)) class'ScrnGameLength';
for(i = 0;i < ScrnGameLength.
}*/
function int SpawnSquad(ZombieVolume ZVol, out array< class<KFMonster> > Squad, optional bool bLogSpawned ){
local int i, j;
local array<NicePack.ZedRecord> zedDatabase;
if(NicePackMutator != none){ zedDatabase = NicePackMutator.zedDatabase; for(i = 0;i < zedDatabase.Length;i ++){ for(j = 0;j < Squad.Length;j ++){ if(zedDatabase[i].bNeedsReplacement && zedDatabase[i].ZedType == Squad[j]) Squad[j] = zeddatabase[i].MeanZedType; } }
}
return super.SpawnSquad(ZVol, Squad, bLogSpawned);
}
function SetupWave(){
Super.SetupWave();
// Event call
NicePackMutator.WaveStart();
}
function RestartPlayer(Controller aPlayer){
Super.RestartPlayer(aPlayer);
if(aPlayer.Pawn != none && NicePlayerController(aPlayer) != none) NicePlayerController(aPlayer).PawnSpawned();
}
State MatchInProgress{
function BeginState(){ Super(Invasion).BeginState();
WaveNum = InitialWave; InvasionGameReplicationInfo(GameReplicationInfo).WaveNumber = WaveNum;
if(NicePackMutator.bInitialTrader) WaveCountDown = NicePackMutator.initialTraderTime + 5; else WaveCountDown = 10;
SetupPickups(); if(ScrnGameLength != none && !ScrnGameLength.LoadWave(WaveNum)) DoWaveEnd();
// Event call NicePackMutator.MatchBegan();
}
function DoWaveEnd(){ Super.DoWaveEnd(); // Event call NicePackMutator.TraderStart();
}
function StartWaveBoss(){ Super.StartWaveBoss(); // Event call NicePackMutator.WaveStart();
}
}
function DramaticEvent(float BaseZedTimePossibility, optional float DesiredZedTimeDuration){
local bool bWasZedTime;
bWasZedTime = bZEDTimeActive;
Super.DramaticEvent(BaseZedTimePossibility, DesiredZedTimeDuration);
// Call event
if(!bWasZedTime && bZEDTimeActive) NicePackMutator.ZedTimeActivated();
}
event Tick(float DeltaTime){
local float TrueTimeFactor;
local Controller C;
if(bZEDTimeActive){ TrueTimeFactor = 1.1 / Level.TimeDilation; CurrentZEDTimeDuration -= DeltaTime * TrueTimeFactor; if(CurrentZEDTimeDuration < (ZEDTimeDuration*0.166) && CurrentZEDTimeDuration > 0 ){ if(!bSpeedingBackUp){ bSpeedingBackUp = true;
for(C = Level.ControllerList;C != none;C = C.NextController){ if(KFPlayerController(C)!= none) KFPlayerController(C).ClientExitZedTime(); } } SetGameSpeed(Lerp( (CurrentZEDTimeDuration/(ZEDTimeDuration*0.166)), 1.0, 0.2 )); } if(CurrentZEDTimeDuration <= 0){ if(bZEDTimeActive) NicePackMutator.ZedTimeDeactivated(); bZEDTimeActive = false; bSpeedingBackUp = false; SetGameSpeed(1.0); ZedTimeExtensionsUsed = 0; }
}
}
function Killed(Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> dmgType){
local GameRules rules;
local ScrnGameRules scrnRules;
local KFSteamStatsAndAchievements StatsAndAchievements;
Super.Killed(Killer, Killed, KilledPawn, dmgType);
if(PlayerController(Killer) != none){ if(NiceMonster(KilledPawn) != none && Killed != Killer){ StatsAndAchievements = KFSteamStatsAndAchievements(PlayerController(Killer).SteamStatsAndAchievements); if(StatsAndAchievements != none){ if(KilledPawn.IsA('NiceZombieStalker') || KilledPawn.IsA('MeanZombieStalker')){ if(class<NiceDamTypeWinchester>(dmgType) != none) StatsAndAchievements.AddStalkerKillWithLAR(); } else if(KilledPawn.IsA('NiceZombieClot') || KilledPawn.IsA('MeanZombieClot')){ if(class<NiceDamTypeWinchester>(dmgType) != none) KFSteamStatsAndAchievements(PlayerController(Killer).SteamStatsAndAchievements).AddClotKillWithLAR(); } if(class<NiceWeaponDamageType>(dmgType) != none){ for(rules = Level.Game.GameRulesModifiers;rules != none;rules = rules.NextGameRules) if(ScrnGameRules(rules) != none){ scrnRules = ScrnGameRules(rules); break; } if(scrnRules != none) class<NiceWeaponDamageType>(dmgType).Static.AwardNiceKill(StatsAndAchievements, KFPlayerController(Killer), KFMonster(KilledPawn), scrnRules.HardcoreLevel); } } }
}
}
// Reloaded to award damage
function int ReduceDamage(int Damage, pawn injured, pawn instigatedBy, vector HitLocation, out vector Momentum, class<DamageType> DamageType){
local NiceMonster niceZed;
local KFPlayerController PC;
niceZed = NiceMonster(Injured);
if(niceZed != none){ if(instigatedBy != none){ PC = KFPlayerController(instigatedBy.Controller); if(class<NiceWeaponDamageType>(damageType) != none && PC != none) class<NiceWeaponDamageType>(damageType).Static.AwardNiceDamage(KFSteamStatsAndAchievements(PC.SteamStatsAndAchievements), Clamp(Damage, 1, Injured.Health), niceZed.scrnRules.HardcoreLevel); }
}
return Super.ReduceDamage(Damage, injured, InstigatedBy, HitLocation, Momentum, DamageType);
}
defaultproperties
{ GameName="Nice Floor" Description="Nice Edition of ScrN Killing Floor game mode (ScrnGameType)."
}

837
sources/NiceHumanPawn.uc Normal file
View File

@ -0,0 +1,837 @@
class NiceHumanPawn extends ScrnHumanPawn
dependson(NiceWeapon);
var bool bReactiveArmorUsed;
var float maniacTimeout;
var float stationaryTime;
var float forcedZedTimeCountDown;
var bool bGotFreeJacket;
var float lastHMGShieldUpdateTime;
var int hmgShieldLevel;
var ScrnHUD scrnHUDInstance;
// Position value means it's a count down for how much invincibility is left,
// Negative value is for counting down a cool-down after a failed head-shot with a melee weapon
var float invincibilityTimer;
var int safeMeleeMisses;
var float ffScale;
var float medicAdrenaliteTime;
var float regenTime;
var bool bZedTimeInvincible;
enum ECalibrationState{
// Calibration isn't available due to lack of ability
CALSTATE_NOABILITY,
CALSTATE_ACTIVE,
CALSTATE_FINISHED
};
var float gunslingerTimer;
var ECalibrationState currentCalibrationState;
var int calibrationScore;
var int calibrationHits, calibrationTotalShots;
var float calibrationRemainingTime;
var array<NiceMonster> calibrateUsedZeds;
var int nicePrevPerkLevel;
var class<NiceVeterancyTypes> nicePrevPerkClass;
struct WeaponTimePair{
var NiceWeapon niceWeap;
var float reloadTime;
};
var array<WeaponTimePair> holsteredReloadList;
var float holsteredReloadCountDown;
var const float defaultInvincibilityDuration;
struct InvincExtentions{
var NiceMonster zed;
var bool hadMiss;
var int extentionsDone;
};
var array<InvincExtentions> zedInvExtList;
var int headshotStack;
replication{
reliable if(Role == ROLE_Authority)
headshotStack, hmgShieldLevel, forcedZedTimeCountDown, maniacTimeout, invincibilityTimer, safeMeleeMisses, ffScale,
currentCalibrationState, calibrationScore, gunslingerTimer;
reliable if(Role == ROLE_Authority)
ClientChangeWeapon;
reliable if(Role < ROLE_AUTHORITY)
ServerUpdateCalibration, ServerCooldownAbility;
}
simulated function bool IsZedExtentionsRecorded(NiceMonster niceZed){
local int i;
for(i = 0;i < zedInvExtList.length;i ++)
if(zedInvExtList[i].zed == niceZed)
return true;
return false;
}
function ReplaceRequiredEquipment(){
Super.ReplaceRequiredEquipment();
RequiredEquipment[0] = String(class'ScrnBalanceSrv.ScrnKnife');//String(class'NicePack.NiceKnife');
RequiredEquipment[1] = String(class'NicePack.NiceWinchester');//String(class'NicePack.Nice9mmPlus');
RequiredEquipment[2] = String(class'ScrnBalanceSrv.ScrnFrag');
RequiredEquipment[3] = String(class'ScrnBalanceSrv.ScrnSyringe');
RequiredEquipment[4] = String(class'KFMod.Welder');
}
simulated function int CalculateCalibrationScore(){
local float accuracy;
accuracy = (float(calibrationHits)) / (float(calibrationTotalShots));
// Very low accuracy (<60%) or not enough shots (<2) - 1 star
if(calibrationTotalShots < 2 || accuracy < 0.6)
return 1;
// Here we definitely have at least 60% accuracy and 2 shots.
// Low accuracy (<80%) or not enough shots (<5) - 2 stars.
if(calibrationTotalShots < 5 || accuracy < 0.8)
return 2;
// Here we definitely have at least 80% accuracy and 5 shots.
// If amount of shots is below 7 - it's 3 stars at most.
if(calibrationTotalShots < 7)
return 3;
// Here we definitely have at least 80% accuracy and 7 shots.
// Unless accuracy is 100% and player made 10 shots - it's 4 stars.
if(accuracy < 1.0 || calibrationTotalShots < 10)
return 4;
// Here we definitely have 100% accuracy and at least 10 shots.
// 5 stars.
return 5;
}
function ServerUpdateCalibration(bool isHit, NiceMonster targetMonster){
local int i;
if(isHit){
for(i = 0;i < calibrateUsedZeds.length;i ++)
if(calibrateUsedZeds[i] == targetMonster)
return;
calibrationHits += 1;
}
calibrationTotalShots += 1;
calibrateUsedZeds[calibrateUsedZeds.length] = targetMonster;
}
simulated function int GetZedExtentionsIndex(NiceMonster niceZed){
local int i;
local int foundIndex;
local InvincExtentions newRecord;
local array<InvincExtentions> newList;
if(niceZed == none || niceZed.health <= 0)
return -1;
foundIndex = -1;
for(i = 0;i < zedInvExtList.Length;i ++)
if(zedInvExtList[i].zed != none && zedInvExtList[i].zed.health > 0){
newList[newList.Length] = zedInvExtList[i];
if(zedInvExtList[i].zed == niceZed)
foundIndex = newList.Length - 1;
}
if(foundIndex < 0){
foundIndex = newList.Length;
newRecord.zed = niceZed;
newList[foundIndex] = newRecord;
}
zedInvExtList = newList;
return foundIndex;
}
simulated function bool TryExtendingInv(NiceMonster niceZed,
bool meleeAttempt, bool wasHeadshot){
local class<NiceVeterancyTypes> niceVet;
local int zedExtIndex;
local bool success;
if(niceZed == none) return false;
niceVet = class'NiceVeterancyTypes'.static.
GetVeterancy(PlayerReplicationInfo);
if(niceVet == none)
return false;
zedExtIndex = GetZedExtentionsIndex(niceZed);
if(zedExtIndex >= 0 && !wasHeadshot)
zedInvExtList[zedExtIndex].hadMiss = true;
if(zedExtIndex >= 0){
success = zedInvExtList[zedExtIndex].extentionsDone
<= niceVet.static.GetInvincibilityExtentions(KFPRI);
success = success && !zedInvExtList[zedExtIndex].hadMiss;
}
else
success = wasHeadshot;
if(invincibilityTimer < 0)
success = false;
if(success){
if(zedExtIndex >= 0)
zedInvExtList[zedExtIndex].extentionsDone ++;
invincibilityTimer = niceVet.static.GetInvincibilityDuration(KFPRI);
safeMeleeMisses = niceVet.static.GetInvincibilitySafeMisses(KFPRI);
return true;
}
if(wasHeadshot)
return false;
if(meleeAttempt){
safeMeleeMisses --;
if(safeMeleeMisses < 0)
ResetMeleeInvincibility();
return false;
}
if(niceVet.static.hasSkill( NicePlayerController(controller),
class'NiceSkillZerkGunzerker')){
invincibilityTimer = class'NiceSkillZerkGunzerker'.default.cooldown;
return false;
}
}
simulated function int FindInHolsteredList(NiceWeapon niceWeap){
local int i;
for(i = 0;i < holsteredReloadList.Length;i ++)
if(holsteredReloadList[i].niceWeap == niceWeap)
return i;
return -1;
}
simulated function ProgressHeadshotStack(bool bIncrease, int minStack, int maxStack, int maxSoftLimit){
if(bIncrease && headshotStack < maxStack)
headshotStack ++;
if(!bIncrease && headshotStack > minStack){
if(headshotStack > maxSoftLimit)
headshotStack = maxSoftLimit;
else
headshotStack --;
}
headshotStack = Max(minStack, headshotStack);
headshotStack = Min(maxStack, headshotStack);
}
simulated function int GetHeadshotStack(int minStack, int maxStack){
headshotStack = Max(minStack, headshotStack);
headshotStack = Min(maxStack, headshotStack);
return headshotStack;
}
simulated function int GetTimeDilationStage(float dilation){
if(dilation <= 0.1)
return 0;
else if(dilation < 1.1)
return 1;
else
return 2;
}
simulated function ResetMeleeInvincibility(){
invincibilityTimer = 0.0;
safeMeleeMisses = 0;
ApplyWeaponStats(weapon);
}
function ServerCooldownAbility(string abilityID){
local int index;
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(controller);
if(nicePlayer == none || nicePlayer.abilityManager == none)
return;
index = nicePlayer.abilityManager.GetAbilityIndex(abilityID);
if(index >= 0)
nicePlayer.abilityManager.SetAbilityState(index, ASTATE_COOLDOWN);
}
simulated function Tick(float deltaTime){
local int index;
local Inventory Item;
local NiceWeapon niceWeap;
local WeaponTimePair newPair;
local array<WeaponTimePair> newWTPList;
local NicePack niceMutator;
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(Controller);
if(Role == Role_AUTHORITY){
// Calibration
if( currentCalibrationState == CALSTATE_ACTIVE
&& calibrationRemainingTime > 0.0){
calibrationScore = CalculateCalibrationScore();
calibrationRemainingTime -= deltaTime;
if(calibrationRemainingTime <= 0 || calibrationScore == 5){
currentCalibrationState = CALSTATE_FINISHED;
calibrateUsedZeds.length = 0;
if(nicePlayer != none && nicePlayer.abilityManager != none)
nicePlayer.abilityManager.SetAbilityState(0, ASTATE_COOLDOWN);
}
}
// Gunslinger
if( gunslingerTimer > 0
&& nicePlayer != none && nicePlayer.abilityManager != none){
gunslingerTimer -= deltaTime;
if(gunslingerTimer <= 0)
nicePlayer.abilityManager.SetAbilityState(1, ASTATE_COOLDOWN);
}
// Regen
if(class'NiceVeterancyTypes'.static.hasSkill(NicePlayerController(Controller), class'NiceSkillMedicRegeneration')){
if(health < healthMax)
regenTime += deltaTime;
while(regenTime > class'NiceSkillMedicRegeneration'.default.regenFrequency){
if(health < healthMax)
health += 1;
else
regenTime = 0.0;
regenTime -= class'NiceSkillMedicRegeneration'.default.regenFrequency;
}
}
// Update adrenaline
medicAdrenaliteTime -= deltaTime;
// This needs updating
if(Level.Game != none)
ffScale = TeamGame(Level.Game).FriendlyFireScale;
else
ffScale = 0;
// Manage melee-invincibility
if(invincibilityTimer < 0){
invincibilityTimer += deltaTime;
if(invincibilityTimer > 0)
ResetMeleeInvincibility();
}
if(invincibilityTimer > 0){
invincibilityTimer -= deltaTime;
if(invincibilityTimer < 0)
ResetMeleeInvincibility();
}
// Manage demo's 'Maniac' skill
maniacTimeout -= deltaTime;
}
super.Tick(deltaTime);
// Restore icons
if(Role < Role_AUTHORITY){
if(scrnHUDInstance == none && nicePlayer != none)
scrnHUDInstance = ScrnHUD(nicePlayer.myHUD);
if(scrnHUDInstance != none && NiceWeapon(weapon) == none){
scrnHUDInstance.ClipsIcon.WidgetTexture = Texture'KillingFloorHUD.HUD.Hud_Ammo_Clip';
scrnHUDInstance.BulletsInClipIcon.WidgetTexture = Texture'KillingFloorHUD.HUD.Hud_Bullets';
scrnHUDInstance.SecondaryClipsIcon.WidgetTexture = Texture'KillingFloor2HUD.HUD.Hud_M79';
}
}
// Update stationary time
if(bIsCrouched && VSize(Velocity) <= 0.0)
stationaryTime += deltaTime;
else
stationaryTime = 0.0;
// Update zed countdown time
if(forcedZedTimeCountDown > 0)
forcedZedTimeCountDown -= deltaTime;
else
forcedZedTimeCountDown = 0.0;
niceMutator = class'NicePack'.static.Myself(Level);
if(niceMutator != none)
niceMutator.ClearWeapProgress();
if(!class'NiceVeterancyTypes'.static.hasSkill(NicePlayerController(Controller), class'NiceSkillEnforcerMultitasker'))
return;
if(Role < ROLE_Authority && nicePlayer != none && nicePlayer.bFlagDisplayWeaponProgress){
// Update weapon progress for this skill
if(niceMutator == none)
return;
for(Item = Inventory; Item != none; Item = Item.Inventory){
niceWeap = NiceWeapon(Item);
if(niceWeap != none && niceWeap != weapon && !niceWeap.IsMagazineFull()){
niceMutator.AddWeapProgress(niceWeap.class, niceWeap.holsteredCompletition,
true, niceWeap.GetMagazineAmmo());
}
}
return;
}
// Auto-reload holstered weapons
holsteredReloadCountDown -= deltaTime;
if(holsteredReloadCountDown <= 0.0){
// Progress current list
for(Item = Inventory; Item != none; Item = Item.Inventory){
niceWeap = NiceWeapon(Item);
if(niceWeap == none || niceWeap == weapon || niceWeap.IsMagazineFull())
continue;
index = FindInHolsteredList(niceWeap);
if(index >= 0){
// Detract time
holsteredReloadList[index].reloadTime -=
0.25 / class'NiceSkillEnforcerMultitasker'.default.reloadSlowDown;
// Add ammo if time is up
if(holsteredReloadList[index].reloadTime < 0.0)
niceWeap.ClientReloadAmmo();
}
}
// Make new list
for(Item = Inventory; Item != none; Item = Item.Inventory){
niceWeap = NiceWeapon(Item);
if(niceWeap == none)
continue;
// Reset holstered completion timer
if(niceWeap == weapon || niceWeap.IsMagazineFull()){
niceWeap.holsteredCompletition = 0.0;
continue;
}
// Update list
index = FindInHolsteredList(niceWeap);
if(index < 0 || holsteredReloadList[index].reloadTime <= 0.0){
newPair.niceWeap = niceWeap;
newPair.reloadTime = niceWeap.TimeUntillReload();
newWTPList[newWTPList.Length] = newPair;
}
else
newWTPList[newWTPList.Length] = holsteredReloadList[index];
// Update holstered completion timer
niceWeap.holsteredCompletition = newWTPList[newWTPList.Length - 1].reloadTime / niceWeap.TimeUntillReload();
niceWeap.holsteredCompletition = 1.0 - niceWeap.holsteredCompletition;
}
holsteredReloadList = newWTPList;
holsteredReloadCountDown = 0.25;
}
}
/*function ServerBuyWeapon(class<Weapon> WClass, float ItemWeight){
local Inventory I;
local NiceSingle nicePistol;
local class<NiceWeaponPickup> WP;
local float Price, Weight, SellValue;
nicePistol = NiceSingle(FindInventoryType(WClass));
if(nicePistol != none && nicePistol.class != WClass)
nicePistol = none;
if((nicePistol != none && nicePistol.bIsDual))
return;
if(nicePistol == none)
super.ServerBuyWeapon(WClass, ItemWeight);
else{
if(!CanBuyNow() || class<NiceWeapon>(WClass) == none)
return;
WP = class<NiceWeaponPickup>(WClass.Default.PickupClass);
if(WP == none)
return;
if(PerkLink == none)
PerkLink = FindStats();
if(PerkLink != none && !PerkLink.CanBuyPickup(WP))
return;
Price = WP.Default.Cost;
if(KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none){
Price *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), WP);
if(class'ScrnBalance'.default.Mut.bBuyPerkedWeaponsOnly
&& WP.default.CorrespondingPerkIndex != 7
&& WP.default.CorrespondingPerkIndex != KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.default.PerkIndex )
return;
}
SellValue = Price * 0.75;
Price = int(Price);
Weight = Class<KFWeapon>(WClass).default.Weight;
if(nicePistol.default.DualClass != none)
Weight = nicePistol.default.DualClass.default.Weight - Weight;
if((Weight > 0 && !CanCarry(Weight)) || PlayerReplicationInfo.Score < Price)
return;
I = Spawn(WClass, self);
if(I != none){
if(KFGameType(Level.Game) != none)
KFGameType(Level.Game).WeaponSpawned(I);
KFWeapon(I).UpdateMagCapacity(PlayerReplicationInfo);
KFWeapon(I).SellValue = SellValue;
I.GiveTo(self);
PlayerReplicationInfo.Score -= Price;
UsedStartCash(Price);
}
else
ClientMessage("Error: Weapon failed to spawn.");
SetTraderUpdate();
}
}
function ServerSellWeapon(class<Weapon> WClass){
local NiceSingle nicePistol;
local NiceDualies niceDual;
nicePistol = NiceSingle(FindInventoryType(WClass));
niceDual = NiceDualies(FindInventoryType(WClass));
if(niceDual != none && niceDual.class != WClass)
niceDual = none;
if(niceDual == none){
// If this a single pistol that is part of dual pistol weapon - double the cost, because it will be cut back by parent 'ServerSellWeapon'
if(nicePistol != none && nicePistol.bIsDual)
nicePistol.SellValue *= 2;
super.ServerSellWeapon(WClass);
}
else{
nicePistol = niceDual.ServerSwitchToSingle();
if(nicePistol == none)
return;
else{
nicePistol.RemoveDual(CurrentWeight);
nicePistol.SellValue *= 0.5;
PlayerReplicationInfo.Score += nicePistol.SellValue;
SetTraderUpdate();
}
}
}*/
// NICETODO: do we even need this one?
simulated function ClientChangeWeapon(NiceWeapon newWeap){
weapon = newWeap;
PendingWeapon = newWeap;
if(newWeap != none){
newWeap.ClientState = WS_Hidden;
ChangedWeapon();
}
PendingWeapon = none;
}
// Validate that client is not hacking.
function bool CanBuyNow(){
local NicePlayerController niceController;
niceController = NicePlayerController(Controller);
if(niceController == none)
return false;
if(NiceGameType(Level.Game) != none && NiceGameType(Level.Game).NicePackMutator != none
&& NiceGameType(Level.Game).NicePackMutator.bIsPreGame)
return true;
if(NiceTSCGame(Level.Game) != none && NiceTSCGame(Level.Game).NicePackMutator != none
&& NiceTSCGame(Level.Game).NicePackMutator.bIsPreGame)
return true;
return Super.CanBuyNow();
}
// Overridden to not modify dual pistols' weapon group
function bool AddInventory(inventory NewItem){
local KFWeapon weap;
local bool GroupChanged;
weap = KFWeapon(NewItem);
if(weap != none){
if(Dualies(weap) != none){
if((DualDeagle(weap) != none || Dual44Magnum(weap) != none || DualMK23Pistol(weap) != none)
&& weap.InventoryGroup != 4 ) {
if(KFPRI != none &&
ClassIsChildOf(KFPRI.ClientVeteranSkill, class'ScrnBalanceSrv.ScrnVetGunslinger'))
weap.InventoryGroup = 3;
else
weap.InventoryGroup = 2;
GroupChanged = true;
}
}
else if(weap.class == class'Single'){
weap.bKFNeverThrow = false;
}
weap.bIsTier3Weapon = true;
}
if(GroupChanged)
ClientSetInventoryGroup(NewItem.class, NewItem.InventoryGroup);
if(super(SRHumanPawn).AddInventory(NewItem)){
if(weap != none && weap.bTorchEnabled)
AddToFlashlightArray(weap.class);
return true;
}
return false;
}
simulated function CookGrenade(){
local ScrnFrag aFrag;
local NiceWeapon niceWeap;
niceWeap = NiceWeapon(Weapon);
if(niceWeap != none)
niceWeap.ClientForceInterruptReload(CANCEL_COOKEDNADE);
if(secondaryItem != none)
return;
if(scrnPerk == none || !scrnPerk.static.CanCookNade(KFPRI, Weapon))
return;
aFrag = ScrnFrag(FindPlayerGrenade());
if(aFrag == none)
return;
if( !aFrag.HasAmmo() || bThrowingNade
|| aFrag.bCooking || aFrag.bThrowingCooked
|| level.timeSeconds - aFrag.cookExplodeTimer <= 0.1)
return;
if( niceWeap == none
|| (niceWeap.bIsReloading && !niceWeap.InterruptReload()))
return;
aFrag.CookNade();
niceWeap.ClientGrenadeState = GN_TempDown;
niceWeap.PutDown();
}
simulated function ThrowGrenade(){
local NiceWeapon niceWeap;
niceWeap = NiceWeapon(Weapon);
if(niceWeap != none)
niceWeap.ClientForceInterruptReload(CANCEL_NADE);
if(bThrowingNade || SecondaryItem != none)
return;
if( niceWeap == none
|| (niceWeap.bIsReloading && !niceWeap.InterruptReload()))
return;
if(playerGrenade == none)
playerGrenade = FindPlayerGrenade();
if(playerGrenade != none && playerGrenade.HasAmmo()){
niceWeap.clientGrenadeState = GN_TempDown;
niceWeap.PutDown();
}
}
simulated function HandleNadeThrowAnim()
{
if(NiceWinchester(Weapon) != none)
SetAnimAction('Frag_Winchester');
/*if(NiceM14EBRBattleRifle(Weapon) != none || NiceMaulerRifle(Weapon) != none)
SetAnimAction('Frag_M14');
else
else if(Crossbow(Weapon) != none)
SetAnimAction('Frag_Crossbow');
else if(NiceM99SniperRifle(Weapon) != none)
SetAnimAction('Frag_M4203');//MEANTODO
else if(NiceAK47AssaultRifle(Weapon) != none)
SetAnimAction('Frag_AK47');
else if(NiceBullpup(Weapon) != none || NiceNailGun(Weapon) != none)
SetAnimAction('Frag_Bullpup');
else if(NiceBoomStick(Weapon) != none)
SetAnimAction('Frag_HuntingShotgun');
else if(NiceShotgun(Weapon) != none || NiceBenelliShotgun(Weapon) != none || NiceTrenchgun(Weapon) != none)
SetAnimAction('Frag_Shotgun');
else if(NiceSCARMK17AssaultRifle(Weapon) != none)
SetAnimAction('Frag_SCAR');
else if(NiceAA12AutoShotgun(Weapon) != none || NiceFNFAL_ACOG_AssaultRifle(Weapon) != none || NiceSPAutoShotgun(Weapon) != none)
SetAnimAction('Frag_AA12');
else if(NiceM4AssaultRifle(Weapon) != none || NiceMKb42AssaultRifle(Weapon) != none)
SetAnimAction('Frag_M4');
else if(NiceThompsonDrumSMG(Weapon) != none)
SetAnimAction('Frag_IJC_spThompson_Drum');*/
Super.HandleNadeThrowAnim();
}
// Remove blur for sharpshooter with a right skill
function bool ShouldBlur(){
local class<NiceVeterancyTypes> niceVet;
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(PlayerReplicationInfo);
if(niceVet != none && niceVet.static.hasSkill(NicePlayerController(Controller), class'NiceSkillEnforcerUnshakable'))
return false;
return true;
}
simulated function AddBlur(Float BlurDuration, float Intensity){
if(shouldBlur())
Super.AddBlur(BlurDuration, Intensity);
}
simulated exec function ToggleFlashlight(){
local NiceWeapon niceWeap;
niceWeap = NiceWeapon(Weapon);
if(niceWeap != none && niceWeap.bUseFlashlightToToggle)
niceWeap.SecondDoToggle();
}
simulated function ApplyWeaponStats(Weapon NewWeapon){
local KFWeapon Weap;
local float weaponWeight;
local class<NiceVeterancyTypes> niceVet;
BaseMeleeIncrease = default.BaseMeleeIncrease;
InventorySpeedModifier = 0;
Weap = KFWeapon(NewWeapon);
SetAmmoStatus();
if(KFPRI != none && Weap != none){
Weap.bIsTier3Weapon = Weap.default.bIsTier3Weapon;
if(Weap.bSpeedMeUp){
if(KFPRI.ClientVeteranSkill != none)
BaseMeleeIncrease += KFPRI.ClientVeteranSkill.Static.GetMeleeMovementSpeedModifier(KFPRI);
InventorySpeedModifier = (default.GroundSpeed * BaseMeleeIncrease);
}
if ( ScrnPerk != none ) {
InventorySpeedModifier +=
default.GroundSpeed * ScrnPerk.static.GetWeaponMovementSpeedBonus(KFPRI, NewWeapon);
}
// Mod speed depending on current weapon's weight
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(PlayerReplicationInfo);
if(niceVet != none)
weaponWeight = niceVet.static.GetPerceivedWeight(KFPlayerReplicationInfo(PlayerReplicationInfo), Weap);
else
weaponWeight = Weap.weight;
InventorySpeedModifier += default.GroundSpeed * (8 - weaponWeight) * 0.025;
// ScrN Armor can slow down players (or even boost) -- PooSH
InventorySpeedModifier -= default.GroundSpeed * GetCurrentVestClass().default.SpeedModifier;
}
}
simulated function ModifyVelocity(float DeltaTime, vector OldVelocity){
local NicePack NicePackMutator;
local NicePlayerController nicePlayer;
local float MovementMod;
local float WeightMod, HealthMod, TempMod;
local float EncumbrancePercentage;
local Inventory Inv;
local KF_StoryInventoryItem StoryInv;
local bool bAllowSlowDown;
local float adrSpeedBonus;
bAllowSlowDown = true;
nicePlayer = NicePlayerController(Controller);
if(class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillEnforcerUnstoppable'))
bAllowSlowDown = false;
super(KFPawn).ModifyVelocity(DeltaTime, OldVelocity);
if(Controller != none)
{
// Calculate encumbrance, but cap it to the maxcarryweight so when we use dev weapon cheats we don't move mega slow
EncumbrancePercentage = (FMin(CurrentWeight, MaxCarryWeight) / default.MaxCarryWeight); //changed MaxCarryWeight to default.MaxCarryWeight
// Calculate the weight modifier to speed
WeightMod = (1.0 - (EncumbrancePercentage * WeightSpeedModifier));
// Calculate the health modifier to speed
HealthMod = ((Health/HealthMax) * HealthSpeedModifier) + (1.0 - HealthSpeedModifier);
// Apply all the modifiers
GroundSpeed = default.GroundSpeed;
MovementMod = 1.0;
if(bAllowSlowDown || HealthMod > 1.0)
MovementMod *= HealthMod;
if(bAllowSlowDown || WeightMod > 1.0)
MovementMod *= WeightMod;
if(KFPRI != none && KFPRI.ClientVeteranSkill != none){
MovementMod *= KFPRI.ClientVeteranSkill.static.GetMovementSpeedModifier(KFPRI, KFGameReplicationInfo(Level.GRI));
}
for(Inv = Inventory;Inv != none;Inv = Inv.Inventory){
TempMod = Inv.GetMovementModifierFor(self);
if(bAllowSlowDown || TempMod > 1.0)
MovementMod *= TempMod;
StoryInv = KF_StoryInventoryItem(Inv);
if(StoryInv != none && StoryInv.bUseForcedGroundSpeed)
{
GroundSpeed = StoryInv.ForcedGroundSpeed;
return;
}
}
if(bTraderSpeedBoost && !KFGameReplicationInfo(Level.GRI).bWaveInProgress)
MovementMod *= TraderSpeedBoost;
if(Health < HealthMax && medicAdrenaliteTime > 0){
// Calulate boos from adrenaline
adrSpeedBonus = Health * (1 - class'NiceSkillMedicAdrenalineShot'.default.speedBoost) +
(100 * class'NiceSkillMedicAdrenalineShot'.default.speedBoost - class'NiceSkillMedicAdrenalineShot'.default.minHealth);
adrSpeedBonus /= (100 - class'NiceSkillMedicAdrenalineShot'.default.minHealth);
adrSpeedBonus = FMin(adrSpeedBonus, class'NiceSkillMedicAdrenalineShot'.default.speedBoost);
adrSpeedBonus = FMax(adrSpeedBonus, 1.0);
MovementMod *= adrSpeedBonus;
}
GroundSpeed = default.GroundSpeed * MovementMod;
AccelRate = default.AccelRate * MovementMod;
if(bAllowSlowDown || InventorySpeedModifier > 0)
GroundSpeed += InventorySpeedModifier;
if(nicePlayer != none && nicePlayer.IsZedTimeActive() && class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillZerkZEDAccelerate'))
AccelRate *= 100;
}
NicePackMutator = class'NicePack'.static.Myself(Level);
if(NicePackMutator != none && NicePackMutator.bIsPreGame && NicePackMutator.bInitialTrader && NicePackMutator.bStillDuringInitTrader)
GroundSpeed = 1;
}
function getFreeJacket(){
if(!bGotFreeJacket && ShieldStrength < LightVestClass.default.ShieldCapacity && class'NiceVeterancyTypes'.static.SomeoneHasSkill(NicePlayerController(Controller), class'NiceSkillSupportArmory')){
if(SetVestClass(LightVestClass)){
ShieldStrength = LightVestClass.default.ShieldCapacity;
bGotFreeJacket = true;
}
}
}
simulated function TakeDamage(int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex){
local int needArmor;
local int healAmount;
local float healPotency;
local bool bOldArmorStops;
local float adrResistance;
local NicePlayerController nicePlayer;
ApplyWeaponStats(Weapon);
if(invincibilityTimer > 0)
return;
nicePlayer = NicePlayerController(Controller);
if(bZedTimeInvincible){
if(nicePlayer != none && nicePlayer.IsZedTimeActive())
return;
else
bZedTimeInvincible = false;
}
// Adrenaline damage decrease
if(medicAdrenaliteTime > 0){
adrResistance = Health * (1 - class'NiceSkillMedicAdrenalineShot'.default.resistBoost) +
(100 * class'NiceSkillMedicAdrenalineShot'.default.resistBoost - class'NiceSkillMedicAdrenalineShot'.default.minHealth);
adrResistance /= (100 - class'NiceSkillMedicAdrenalineShot'.default.minHealth);
adrResistance = FMin(adrResistance, class'NiceSkillMedicAdrenalineShot'.default.resistBoost);
adrResistance = FMax(adrResistance, 1.0);
Damage *= adrResistance;
}
if(nicePlayer != none && nicePlayer.IsZedTimeActive()
&& class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillZerkZEDUnbreakable'))
return;
if(hmgShieldLevel > 0 && class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillEnforcerFullCounter')){
if(Damage < 20 && InstigatedBy.default.HealthMax < 1500){
Damage *= class'NiceSkillEnforcerFullCounter'.default.damageReduction;
hmgShieldLevel --;
}
else{
if(hmgShieldLevel == class'NiceSkillEnforcerFullCounter'.default.layersAmount)
Damage *= class'NiceSkillEnforcerFullCounter'.default.damageReduction * float(hmgShieldLevel) /
float(class'NiceSkillEnforcerFullCounter'.default.layersAmount);
hmgShieldLevel = 0;
}
}
lastHMGShieldUpdateTime = Level.TimeSeconds;
if(damageType != none && class<NiceDamTypeDrug>(damageType) == none){
bOldArmorStops = damageType.default.bArmorStops;
if(class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillHeavyCoating'))
damageType.default.bArmorStops = true;
}
lastExplosionDistance = 0.0; // hack, but scrn fucks with usotherwise
super.TakeDamage(Damage, InstigatedBy, hitLocation, Momentum, damageType, HitIndex);
// Commando's zed time
if( forcedZedTimeCountDown <= 0.0
&& health < class'NiceSkillCommandoCriticalFocus'.default.healthBoundary && KFGameType(Level.Game) != none
&& class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillCommandoCriticalFocus') ){
KFGameType(Level.Game).DramaticEvent(1.0);
forcedZedTimeCountDown = class'NiceSkillCommandoCriticalFocus'.default.cooldown;
}
if(damageType != none)
damageType.default.bArmorStops = bOldArmorStops;
// Do heavy mg's armor healing
if(class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillHeavySafeguard') && health < HealthMax * 0.5 && ShieldStrength > 0){
healAmount = HealthMax - health;
healPotency = 1.0;
if(health < HealthMax * 0.25)
healPotency = 2.0;
else if(health < HealthMax * 0.1)
healPotency = 10.0;
needArmor = float(healAmount) * healPotency * class'NiceSkillHeavySafeguard'.default.healingCost;
ShieldStrength -= needArmor;
if(ShieldStrength < 0)
ShieldStrength = 0;
health += HealAmount * 0.5;
TakeHealing(self, HealAmount * 0.5, HealPotency);
}
if(ShieldStrength <= 0)
getFreeJacket();
}
function int ShieldAbsorb(int damage){
if(ShieldStrength > 0 && class'NiceVeterancyTypes'.static.HasSkill(NicePlayerController(Controller), class'NiceSkillHeavySafeguard'))
return damage;
return super.ShieldAbsorb(damage);
}
function Timer(){
if(BurnDown > 0 && BurnInstigator != self && KFPawn(BurnInstigator) != none)
LastBurnDamage *= 1.8;
super(SRHumanPawn).Timer();
// tick down health if it's greater than max
if(Health > HealthMax){
if(Health > 100)
Health -= 5;
if(Health < HealthMax)
Health = HealthMax;
}
SetAmmoStatus();
ApplyWeaponFlashlight(true);
// Regenerate HMG's full counter shield
if(hmgShieldLevel < class'NiceSkillEnforcerFullCounter'.default.layersAmount && Level.TimeSeconds - lastHMGShieldUpdateTime > class'NiceSkillEnforcerFullCounter'.default.coolDown){
lastHMGShieldUpdateTime = Level.TimeSeconds;
hmgShieldLevel ++;
}
}
/*simulated function Fire(optional float F){
local bool bRecManualReload;
local NiceSingle singleWeap;
local ScrnPlayerController PC;
singleWeap = NiceSingle(weapon);
PC = ScrnPlayerController(Controller);
if(PC != none && singleWeap != none && singleWeap.bIsDual && singleWeap.otherMagazine > 0){
bRecManualReload = PC.bManualReload;
PC.bManualReload = false;
super.Fire(F);
PC.bManualReload = bRecManualReload;
}
else
super.Fire(F);
}*/
function float AssessThreatTo(KFMonsterController Monster, optional bool CheckDistance){
return super(SRHumanPawn).AssessThreatTo(Monster, CheckDistance);
}
function VeterancyChanged(){
local NicePlayerController nicePlayer;
if(KFPRI == none)
return;
nicePlayer = NicePlayerController(Controller);
nicePrevPerkLevel = KFPRI.ClientVeteranSkillLevel;
nicePrevPerkClass = class<NiceVeterancyTypes>(KFPRI.ClientVeteranSkill);
if(nicePlayer != none && nicePlayer.abilityManager != none)
nicePlayer.abilityManager.ClearAbilities();
if(nicePrevPerkClass != none && Role == Role_AUTHORITY)
nicePrevPerkClass.static.SetupAbilities(KFPRI);
if(nicePlayer != none){
nicePlayer.TriggerSelectEventOnPerkChange(nicePrevPerkClass,
class<NiceVeterancyTypes>(KFPRI.ClientVeteranSkill));
}
super.VeterancyChanged();
}
/*simulated function AltFire(optional float F){
if(NiceMedicGun(Weapon) != none)
super(SRHumanPawn).AltFire(F);
else
super.AltFire(F);
}*/
defaultproperties
{
defaultInvincibilityDuration=2.000000
BaseMeleeIncrease=0.000000
}

1099
sources/NicePack.uc Normal file

File diff suppressed because it is too large Load Diff

126
sources/NicePathBuilder.uc Normal file
View File

@ -0,0 +1,126 @@
//==============================================================================
// NicePack / NicePathBuilder
//==============================================================================
// - Class that allows to build string representation of paths like:
// "/home/dk", "/Weapons/M14Ebr/StateMachine", "Store/Weapons[7].ID"
// that are used in various places in this mutator.
// - Reserved symbol that can't be used in names provided by user: '/'.
// - Works by appending new elements to the end of already existed path
// like a stack, making it possible to either remove elements from the end
// or flush and clear the whole accumulated path.
// - Designed to support flow-syntax allowing user to build paths like follows:
// path.AddElement("").AddElement("home").AddElement("dk").ToString()
// => "/home/dk/"
// path.AddElement("Store").AddElement("Weapons").AddElement("")
// .ToString()
// => "Store/Weapons/"
// - Element names can be empty:
// /folder//another/
// above contains following names (in order): "folder", "", "another", "".
// - Can parse preexistent path from string,
// which may lead to a failed state in case of incorrect formatting.
//==============================================================================
// Class hierarchy: Object > NicePathBuilder
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NicePathBuilder extends Object;
// 'true' if path is in an invalid state, meaning no operations except
// 'Flush' and 'Parse' (that completely clear current path)
// can be performed.
var protected bool _isInvalid;
// Elements of currently built path.
var protected array<string> currentPath;
// Constants that store reserved symbols.
var const string resElementSeparator;
// Checks if path is currently empty.
// Invalid path isn't considered empty.
function bool IsEmpty(){
if(IsInvalid())
return false;
return (currentPath.length <= 0);
}
function bool IsInvalid(){
return _isInvalid;
}
// Forcefully enters this path into an invalid state.
function NicePathBuilder Fail(){
_isInvalid = true;
return self;
}
// Checks if passed name valid, i.e. doesn't contain any reserved characters.
function bool IsNameValid(string nameToCheck){
if(InStr(nameToCheck, resElementSeparator) >= 0)
return false;
return true;
}
// 'AddElement(<elementName>)' effectively adds '/<elementName>' to the path.
// ~ If given name contains reserved characters - path will become invalid.
function NicePathBuilder AddElement(string elementName){
if(IsInvalid()) return self;
if(!IsNameValid(elementName)) return Fail();
currentPath[currentPath.length] = elementName;
return self;
}
// Returns string representation of this path.
// Returns empty string if path is invalid or empty.
function string ToString(){
local int i;
local string accumulator;
if(IsInvalid()) return "";
if(IsEmpty()) return "";
accumulator = currentPath[0];
for(i = 1;i < currentPath.length;i ++)
accumulator = accumulator $ resElementSeparator $ currentPath[i];
return accumulator;
}
// Removes several last elements.
function NicePathBuilder RemoveMany(int howMuchToRemove){
local int newLength;
if(IsInvalid()) return self;
newLength = currentPath.length - howMuchToRemove;
if(newLength < 0)
newLength = 0;
currentPath.length = newLength;
return self;
}
// Removes last element, identical to 'RemoveMany(1)'.
function NicePathBuilder RemoveLast(){
return RemoveMany(1);
}
// Returns array of elements in the current path.
function array<string> GetElements(){
return currentPath;
}
// Clears current path and resets absolute path flag to 'false'.
function NicePathBuilder Flush(){
currentPath.length = 0;
_isInvalid = false;
return self;
}
function NicePathBuilder Parse(string toParse){
Flush();
Split(toParse, resElementSeparator, currentPath);
return self;
}
defaultproperties
{
resElementSeparator="/"
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
class NiceRandomItemSpawn extends ScrnRandomItemSpawn;
defaultproperties
{
PickupClasses(0)=Class'NicePack.NiceWinchesterPickup'
/*PickupClasses(0)=Class'NicePack.Nice9mmPlusPickup'
PickupClasses(1)=Class'NicePack.NiceShotgunPickup'
PickupClasses(2)=Class'NicePack.NiceBullpupPickup'
PickupClasses(3)=Class'NicePack.NiceMagnumPickup'
PickupClasses(4)=Class'NicePack.NiceWinchesterPickup'
PickupClasses(5)=Class'NicePack.NiceM79Pickup'
PickupClasses(8)=Class'NicePack.NiceMAC10Pickup'*/
}

View File

@ -0,0 +1,459 @@
//==============================================================================
// NicePack / NiceReplicationInfo
//==============================================================================
// Manages sending messages from clients to server.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceReplicationInfo extends ReplicationInfo
dependson(NiceBullet);
var NicePack Mut;
replication{
reliable if(Role < ROLE_Authority)
ServerDamagePawn, ServerDealDamage, ServerDealMeleeDamage,
ServerUpdateHit, ServerExplode, ServerJunkieExtension,
/*ServerStickProjectile*/ServerHealTarget;
}
// Makes server to spawn a sticked projectile.
/*simulated function ServerStickProjectile
(
KFHumanPawn instigator,
Actor base,
name bone,
Vector shift,
Rotator direction,
NiceBullet.ExplosionData expData
){
class'NiceProjectileSpawner'.static.
StickProjectile(instigator, base, bone, shift, direction, expData);
}*/
// Returns scale value that determines how to scale explosion damage to
// given victim.
// Method assumes that a valid victim was passed.
simulated function float GetDamageScale(Actor victim, Vector explosionLocation,
Vector victimPoint,
float explRadius, float explExp){
local Vector dirToVictim;
local float scale;
local float distToVictim;
local KFPawn victimKFPawn;
local KFMonster victimMonster;
dirToVictim = victimPoint - explosionLocation;
distToVictim = FMax(1.0, VSize(dirToVictim));
scale = 1 - FMax(0.0, (distToVictim - victim.collisionRadius) / explRadius);
if(scale <= 0)
scale = 0;
else
scale = scale ** explExp;
// Try scaling for exposure level (only available to monsters and KFPawns)
victimKFPawn = KFPawn(victim);
victimMonster = KFMonster(victim);
if(victimKFPawn != none && victimKFPawn.health <= 0)
scale *= victimKFPawn.GetExposureTo(explosionLocation);
else if(victimMonster != none && victimMonster.health <= 0)
scale *= victimMonster.GetExposureTo(explosionLocation);
return scale;
}
// Returns scale values that determine how to scale explosion damage to
// given victim.
// There's two scale values due to how kf1 calculated explosion damage:
// by scaling it according to distance to two different points
// (location of the victim and a point 75% of collision height higher).
// First scale will be the one with the highest number.
// Method assumes that a valid victim was passed.
simulated function CalculateDamageScales( out float scale1, out float scale2,
Actor victim,
Vector explosionLocation,
float explRadius, float explExp){
local Vector victimPoint1, victimPoint2;
local float swap;
victimPoint1 = victim.location;
victimPoint2 = victim.location;
victimPoint2.z += victim.CollisionHeight * 0.75;
scale1 = GetDamageScale(victim, explosionLocation, victimPoint1,
explRadius, explExp);
scale2 = GetDamageScale(victim, explosionLocation, victimPoint2,
explRadius, explExp);
if(scale1 < scale2){
swap = scale1;
scale1 = scale2;
scale2 = swap;
}
}
// Simulates an explosion on a server.
simulated function ServerExplode
(
float explDamage,
float explRadius,
float explExp,
class<NiceWeaponDamageType> explDmgType,
float momentum,
Vector explLocation,
Pawn instigator,
optional bool allowDoubleExplosion,
optional Actor explosionTarget,
optional vector explosiveDirection
){
local Actor victim;
local int numKilled;
local Vector dirToVictim;
local Vector hitLocation;
local float scale1, scale2;
if(Role < ROLE_Authority) return;
foreach CollidingActors(class'Actor', victim, explRadius, explLocation){
if(victim == none || victim == self) continue;
if(victim.role < ROLE_Authority) continue;
if(ExtendedZCollision(victim) != none) continue;
if(Trigger(victim) != none) continue;
dirToVictim = Normal(victim.location - explLocation);
hitLocation = victim.location - 0.5 *
(victim.collisionHeight + victim.collisionRadius) * dirToVictim;
CalculateDamageScales( scale1, scale2,
victim, explLocation, explRadius, explExp);
// Deal main damage
if(scale1 > 0){
ServerDealDamage( victim, explDamage * scale1, instigator,
hitLocation, scale1 * momentum * dirToVictim,
explDmgType);
}
// Deal secondary damage
if(allowDoubleExplosion && victim != none && scale2 > 0){
ServerDealDamage( victim, explDamage * scale2, instigator,
hitLocation, scale2 * momentum * dirToVictim,
explDmgType);
}
if(NiceMonster(victim) != none && NiceMonster(victim).health <= 0)
numKilled ++;
}
if(numKilled >= 4)
KFGameType(level.game).DramaticEvent(0.05);
else if(numKilled >= 2)
KFGameType(level.game).DramaticEvent(0.03);
}
simulated function ServerDamagePawn
(
KFPawn injured,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
Class<DamageType> damageType,
int hitPoint
){
local array<int> hitPoints;
if(injured == none) return;
hitPoints[0] = hitPoint;
injured.ProcessLocationalDamage(damage, instigatedBy, hitLocation, momentum,
damageType, hitPoints);
}
simulated function HandleNiceHealingMechanicsAndSkills
(
NiceHumanPawn healer,
NiceHumanPawn healed,
float healPotency
){
local bool hasZEDHeavenCanceller;
local NicePlayerController nicePlayer;
if(healer == none || healed == none) return;
nicePlayer = NicePlayerController(healer.controller);
if(nicePlayer == none)
return;
if(class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicAdrenalineShot')){
healed.medicAdrenaliteTime =
class'NiceSkillMedicAdrenalineShot'.default.boostTime;
}
if(class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicSymbioticHealth')){
healer.TakeHealing(
healer,
healer.healthMax *
class'NiceSkillMedicSymbioticHealth'.default.selfBoost,
healPotency,
KFWeapon(healer.weapon));
}
hasZEDHeavenCanceller = class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicZEDHeavenCanceller');
if(nicePlayer.IsZedTimeActive() && hasZEDHeavenCanceller){
healed.health = healed.healthMax;
healed.bZedTimeInvincible = true;
}
}
simulated function RemovePoisonAndBleed(NiceHumanPawn healed){
local Inventory I;
local MeanReplicationInfo MRI;
// No bleeding
MRI = class'MeanReplicationInfo'.static.
findSZri(healed.PlayerReplicationInfo);
if(MRI != none)
MRI.stopBleeding();
// No poison
if(healed.inventory == none) return;
for(I = healed.inventory; I != none; I = I.inventory){
if(MeanPoisonInventory(I) != none)
I.Destroy();
}
}
// Tells server to heal given human pawn.
simulated function ServerHealTarget(NiceHumanPawn healed, float charPotency,
Pawn instigator){
local NiceHumanPawn healer;
local KFPlayerReplicationInfo KFPRI;
local float healTotal;
local float healPotency;
if(instigator == none || healed == none) return;
if(healed.health <= 0 || healed.health >= healed.healthMax) return;
KFPRI = KFPlayerReplicationInfo(instigator.PlayerReplicationInfo);
if(KFPRI == none || KFPRI.ClientVeteranSkill == none)
return;
healer = NiceHumanPawn(instigator);
if(healer == none)
return;
healPotency = KFPRI.ClientVeteranSkill.static.GetHealPotency(KFPRI);
healTotal = charPotency * healPotency;
healer.AlphaAmount = 255;
/* if(NiceMedicGun(healer.weapon) != none)
NiceMedicGun(healer.weapon).ClientSuccessfulHeal(healer, healed);
if(healed.health >= healed.healthMax){
healed.GiveHealth(healTotal, healed.healthMax);
return;
}*/
HandleNiceHealingMechanicsAndSkills(healer, healed, healPotency);
if(healed.health < healed.healthMax){
healed.TakeHealing( healed, healTotal, healPotency,
KFWeapon(instigator.weapon));
}
RemovePoisonAndBleed(healed);
}
simulated function HandleNiceDamageMechanicsAndSkills
(
NiceMonster niceZed,
out int damage,
NiceHumanPawn nicePawn,
out Vector hitLocation,
out Vector momentum,
class<NiceWeaponDamageType> damageType,
out float headshotLevel,
out float lockonTime
){
local bool hasZEDFrenzy;
local bool hasTranquilizer;
local bool hasVorpalBlade;
local NiceMonsterController zedController;
local NicePlayerController nicePlayer;
if(niceZed == none) return;
if(nicePawn == none) return;
nicePlayer = NicePlayerController(nicePawn.controller);
if(nicePlayer == none)
return;
// Medic's skills
if(class<NiceDamTypeMedicDart>(damageType) != none){
hasTranquilizer = class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicTranquilizer');
hasZEDFrenzy = class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicZEDFrenzy');
// Medic's suppression
if(hasTranquilizer)
niceZed.mind = FMin(niceZed.mind, 0.5);
// Medic's frenzy
if(hasZEDFrenzy && nicePlayer.IsZedTimeActive()){
niceZed.madnessCountDown =
class'NiceSkillMedicZEDFrenzy'.default.madnessTime;
zedController = NiceMonsterController(niceZed.controller);
if(zedController != none)
zedController.FindNewEnemy();
}
}
// Zerker's skills
if(class<niceDamageTypeVetBerserker>(DamageType) != none){
hasVorpalBlade = class'NiceVeterancyTypes'.static.
HasSkill(nicePlayer, class'NiceSkillZerkVorpalBlade');
if( hasVorpalBlade && headshotLevel > 0.0
&& !nicePawn.IsZedExtentionsRecorded(niceZed))
damage *= class'NiceSkillZerkVorpalBlade'.default.damageBonus;
}
}
simulated function UpdateMeleeInvincibility
(
NiceMonster niceZed,
int damage,
NiceHumanPawn nicePawn,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
float headshotLevel,
bool mainTarget
){
local bool hasGunzerker;
local bool allowedInvincibility;
if(nicePawn == none) return;
if(niceZed == none) return;
allowedInvincibility = class'NiceVeterancyTypes'.static.
GetVeterancy(nicePawn.PlayerReplicationInfo) == class'NiceVetBerserker';
allowedInvincibility = allowedInvincibility || niceZed.headHealth <= 0;
if(!allowedInvincibility)
return;
// Handle non-melee cases (gunzerker-invincibility)
hasGunzerker = class'NiceVeterancyTypes'.static.
hasSkill( NicePlayerController(nicePawn.controller),
class'NiceSkillZerkGunzerker');
if(hasGunzerker && class<niceDamageTypeVetBerserker>(damageType) == none)
nicePawn.TryExtendingInv(niceZed, false, headshotLevel > 0.0);
// Handle melee-cases
if(mainTarget && class<niceDamageTypeVetBerserker>(damageType) != none)
nicePawn.TryExtendingInv(niceZed, true, headshotLevel > 0.0);
nicePawn.ApplyWeaponStats(nicePawn.weapon);
}
simulated function UpdateArdour(bool isKill, NicePlayerController nicePlayer){
local bool hasArdour;
local NiceHumanPawn nicePawn;
local float cooldownChange;
if(nicePlayer == none) return;
if(nicePlayer.abilityManager == none) return;
nicePawn = NiceHumanPawn(nicePlayer.pawn);
if(nicePawn == none)
return;
hasArdour = class'NiceVeterancyTypes'.static.
hasSkill( nicePlayer,
class'NiceSkillSharpshooterArdour');
if(!hasArdour)
return;
cooldownChange =
class'NiceSkillSharpshooterArdour'.default.
headshotKillReduction[nicePawn.calibrationScore - 1];
if(!isKill){
cooldownChange *=
class'NiceSkillSharpshooterArdour'.default.justHeadshotReduction;
}
nicePlayer.abilityManager.AddToCooldown(1, -cooldownChange);
}
// Returns 'true' if before calling it zed was alive and had a head.
simulated function bool ServerDealDamageBase
(
Actor other,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
optional float headshotLevel,
optional float lockonTime
){
local NiceMonster niceZed;
local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer;
local bool zedWasAliveWithHead;
if(other == none) return false;
niceZed = NiceMonster(other);
nicePawn = NiceHumanPawn(InstigatedBy);
if(nicePawn != none)
nicePlayer = NicePlayerController(nicePawn.Controller);
if(niceZed == none || nicePlayer == none){
other.TakeDamage( damage, instigatedBy,
hitLocation, momentum, damageType);
return false;
}
zedWasAliveWithHead = (niceZed.health > 0.0) && (niceZed.headHealth > 0.0);
HandleNiceDamageMechanicsAndSkills( niceZed, damage, nicePawn,
hitLocation, momentum, damageType,
headshotLevel, lockonTime);
niceZed.TakeDamageClient( damage, instigatedBy, hitLocation, momentum,
damageType, headshotLevel, lockonTime);
return zedWasAliveWithHead;
}
// Tells server to damage given pawn.
simulated function ServerDealDamage
(
Actor other,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
optional float headshotLevel,
optional float lockonTime
){
local NiceMonster niceZed;
local bool zedWasAliveWithHead;
if(headshotLevel > 0)
UpdateArdour(false, NicePlayerController(instigatedBy.controller));
zedWasAliveWithHead = ServerDealDamageBase( other, damage, instigatedBy,
hitLocation, momentum,
damageType, headshotLevel,
lockonTime);
if(!zedWasAliveWithHead)
return;
niceZed = NiceMonster(other);
if( niceZed != none
&& (niceZed.health < 0 || niceZed.headHealth < 0))
UpdateArdour(true, NicePlayerController(instigatedBy.controller));
UpdateMeleeInvincibility( niceZed, damage,
NiceHumanPawn(instigatedBy),
hitLocation, momentum, damageType,
headshotLevel, true);
}
// Tells server to damage given pawn with melee.
// Difference with 'ServerDealDamage' is that this function passes data about
// whether our target was 'main' target of melee swing
// or was hit by AOE effect.
simulated function ServerDealMeleeDamage
(
Actor other,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
bool mainTarget,
optional float headshotLevel
){
local bool zedWasAliveWithHead;
zedWasAliveWithHead = ServerDealDamageBase( other, damage, instigatedBy,
hitLocation, momentum,
damageType, headshotLevel, 0.0);
if(!zedWasAliveWithHead)
return;
UpdateMeleeInvincibility( NiceMonster(other), damage,
NiceHumanPawn(instigatedBy),
hitLocation, momentum, damageType,
headshotLevel, mainTarget);
}
simulated function ServerUpdateHit
(
Actor tpActor,
Actor hitActor,
Vector clientHitLoc,
Vector hitNormal,
optional Vector hitLocDiff
){
local KFWeaponAttachment weapAttach;
weapAttach = KFWeaponAttachment(tpActor);
if(weapAttach != none)
weapAttach.UpdateHit(hitActor, clientHitLoc + hitLocDiff, hitNormal);
}
simulated function ServerJunkieExtension( NicePlayerController player,
bool isHeadshot){
local NiceGameType niceGame;
local class<NiceVeterancyTypes> niceVet;
if(player == none || player.bJunkieExtFailed) return;
niceGame = NiceGameType(player.Level.Game);
if(niceGame == none || !niceGame.bZEDTimeActive)
return;
niceVet = class'NiceVeterancyTypes'.static.
GetVeterancy(player.PlayerReplicationInfo);
if(niceVet == none)
return;
if(niceVet.static.hasSkill(player, class'NiceSkillSharpshooterZEDAdrenaline')){
if(!isHeadshot)
player.bJunkieExtFailed = true;
else if(Mut != none)
Mut.JunkieZedTimeExtend();
}
}
defaultproperties
{
}

79
sources/NiceRules.uc Normal file
View File

@ -0,0 +1,79 @@
class NiceRules extends GameRules;
var ScrnGameRules ScrnRules;
function PostBeginPlay(){
if(Level.Game.GameRulesModifiers == none) Level.Game.GameRulesModifiers = Self;
else{ // We need to be the ones giving achievements first Self.AddGameRules(Level.Game.GameRulesModifiers); Level.Game.GameRulesModifiers = Self;
}
if(NicePack(Owner) != none) ScrnRules = NicePack(Owner).ScrnMut.GameRules;
else{ Log("Wrong owner! Owner must be NicePack!"); Destroy();
}
}
function bool CheckEndGame(PlayerReplicationInfo Winner, string Reason){
local bool bWin;
local string MapName;
if(Level.Game.IsInState('PendingMatch')) return false;
if(Level.Game.bGameEnded) return true;
if(NextGameRules != none && !NextGameRules.CheckEndGame(Winner,Reason)) return false;
if(ScrnRules.Mut.bStoryMode) bWin = Reason ~= "WinAction";
else{ bWin = KFGameReplicationInfo(Level.GRI) != none && KFGameReplicationInfo(Level.GRI).EndGameType == 2;
}
if(bWin){ // Map achievements MapName = ScrnRules.Mut.KF.GetCurrentMapName(Level); ScrnRules.CheckMapAlias(MapName); GiveMapAchievements(MapName);
}
return true;
}
// We would never get ScrN Sui and Hoe achievs with our new zeds, so let's add them ourselves. For different reasons.
function GiveMapAchievements(optional String MapName){
local bool bCustomMap, bGiveHardAch, bGiveSuiAch, bGiveHoeAch, bNewAch;
local ScrnPlayerInfo SPI;
local ClientPerkRepLink PerkLink;
local TeamInfo WinnerTeam;
WinnerTeam = TeamInfo(Level.Game.GameReplicationInfo.Winner);
if(ScrnRules.Mut.bStoryMode){ bGiveHardAch = Level.Game.GameDifficulty >= 4; bGiveSuiAch = Level.Game.GameDifficulty >= 5; bGiveHoeAch = Level.Game.GameDifficulty >= 7;
}
else{ bGiveHardAch = ScrnRules.HardcoreLevel >= 5; bGiveSuiAch = ScrnRules.HardcoreLevel >= 10; bGiveHoeAch = ScrnRules.HardcoreLevel >= 15;
}
for (SPI = ScrnRules.PlayerInfo;SPI != none;SPI = SPI.NextPlayerInfo){ if (SPI.PlayerOwner == none || SPI.PlayerOwner.PlayerReplicationInfo == none) continue; PerkLink = SPI.GetRep(); if(PerkLink == none) continue; if(WinnerTeam != none && SPI.PlayerOwner.PlayerReplicationInfo.Team != WinnerTeam) continue; // no candies for loosers // additional achievements that are granted only when surviving the game if(ScrnPlayerController(SPI.PlayerOwner) != none && !ScrnPlayerController(SPI.PlayerOwner).bChangedPerkDuringGame) SPI.ProgressAchievement('PerkFavorite', 1);
//unlock "Normal" achievement and see if the map is found bCustomMap = ScrnRules.MapAchClass.static.UnlockMapAchievement(PerkLink, MapName, 0) == -2; bNewAch = false; if(bCustomMap){ //map not found - progress custom map achievements if(bGiveHardAch) ScrnRules.AchClass.static.ProgressAchievementByID(PerkLink, 'WinCustomMapsHard', 1); if(bGiveSuiAch) ScrnRules.AchClass.static.ProgressAchievementByID(PerkLink, 'WinCustomMapsSui', 1); if(bGiveHoeAch) ScrnRules.AchClass.static.ProgressAchievementByID(PerkLink, 'WinCustomMapsHoE', 1); ScrnRules.AchClass.static.ProgressAchievementByID(PerkLink, 'WinCustomMapsNormal', 1); ScrnRules.AchClass.static.ProgressAchievementByID(PerkLink, 'WinCustomMaps', 1); } else{ //map found - give related achievements if(bGiveHardAch) ScrnRules.MapAchClass.static.UnlockMapAchievement(PerkLink, MapName, 1); if(bGiveSuiAch) ScrnRules.MapAchClass.static.UnlockMapAchievement(PerkLink, MapName, 2); if(bGiveHoeAch) ScrnRules.MapAchClass.static.UnlockMapAchievement(PerkLink, MapName, 3); }
}
}
function int NetDamage(int OriginalDamage, int Damage, pawn injured, pawn instigatedBy, vector HitLocation, out vector Momentum, class<DamageType> DamageType){
local TeamGame TG;
TG = TeamGame(Level.Game);
if(KFPawn(injured) != none && TG != none && Damage > 0 && class<DamTypeEnemyBase>(DamageType) == none){ if((KFPawn(instigatedBy) != none || FakePlayerPawn(instigatedBy) != none) && (instigatedBy.PlayerReplicationInfo == none || instigatedBy.PlayerReplicationInfo.bOnlySpectator)){ Momentum = vect(0,0,0); if(NoFF(injured, TG.FriendlyFireScale)) return 0; else if(OriginalDamage == Damage) return Damage * TG.FriendlyFireScale; } else if(instigatedBy == none && !DamageType.default.bCausedByWorld){ Momentum = vect(0,0,0); if(NoFF(injured, TG.FriendlyFireScale)) return 0; else if(OriginalDamage == Damage) return Damage * TG.FriendlyFireScale; }
}
return super.NetDamage(OriginalDamage, Damage, injured, instigatedBy, HitLocation, Momentum, DamageType);
}
function bool NoFF(Pawn injured, float FF){
return (FF == 0.0 || (Vehicle(injured) != none && Vehicle(injured).bNoFriendlyFire));
}
function RaiseHardcoreLevel(float inc, string reason){
local string s;
local Controller P;
local NicePlayerController nicePlayer;
if(ScrnRules.HardcoreLevelFloat < ScrnRules.HardcoreLevel) ScrnRules.HardcoreLevelFloat = ScrnRules.HardcoreLevel;
ScrnRules.HardcoreLevelFloat += inc;
ScrnRules.HardcoreLevel = int(ScrnRules.HardcoreLevelFloat + 0.01);
ScrnRules.Mut.HardcoreLevel = clamp(ScrnRules.HardcoreLevel, 0, 255);
ScrnRules.Mut.NetUpdateTime = Level.TimeSeconds - 1;
s = ScrnRules.msgHardcore;
ReplaceText(s, "%a", String(ScrnRules.HardcoreLevel));
ReplaceText(s, "%i", String(inc));
ReplaceText(s, "%r", reason);
for(P = Level.ControllerList; P != none; P = P.nextController){ nicePlayer = NicePlayerController(P); if(nicePlayer != none && nicePlayer.bFlagShowHLMessages) nicePlayer.ClientMessage(s);
}
}
function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> damageType, vector HitLocation){
local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(Killed.controller);
nicePawn = NiceHumanPawn(Killed);
if(nicePawn != none && (!nicePawn.bReactiveArmorUsed) && class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillDemoReactiveArmor')){ nicePawn.bReactiveArmorUsed = true; nicePlayer.niceRI.ServerExplode(class'NiceSkillDemoReactiveArmor'.default.baseDamage, class'NiceSkillDemoReactiveArmor'.default.explRadius, class'NiceSkillDemoReactiveArmor'.default.explExponent, class'NiceDamTypeDemoSafeExplosion', class'NiceSkillDemoReactiveArmor'.default.explMomentum, killed.location, killed, true ); return true;
}
if(NextGameRules != none) return NextGameRules.PreventDeath(Killed, Killer, damageType, HitLocation);
return false;
}
defaultproperties
{
}

9
sources/NiceSoundCls.uc Normal file
View File

@ -0,0 +1,9 @@
class NiceSoundCls extends Effects;
var Sound effectSound;
var float effectVolume;
simulated function PostBeginPlay(){
if(effectSound != none) PlaySound(effectSound,, effectVolume);
}
defaultproperties
{ DrawType=DT_None LifeSpan=0.100000
}

View File

@ -0,0 +1,20 @@
//==============================================================================
// NicePack / NiceAbilitiesAdapter
//==============================================================================
// Temporary stand-in for future functionality.
// Use this class to catch events from players' abilities.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceAbilitiesAdapter extends Object;
var LevelInfo level;
static function AbilityActivated( string abilityID, NicePlayerController relatedPlayer);
static function AbilityAdded( string abilityID, NicePlayerController relatedPlayer);
static function AbilityRemoved( string abilityID, NicePlayerController relatedPlayer);
static function ModAbilityCooldown( string abilityID, NicePlayerController relatedPlayer, out float cooldown);
defaultproperties
{
}

View File

@ -0,0 +1,57 @@
//==============================================================================
// NicePack / NiceAbilitiesEvents
//==============================================================================
// Temporary stand-in for future functionality.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceAbilitiesEvents extends Object;
var array< class<NiceAbilitiesAdapter> > adapters;
// If adapter was already added also returns 'false'.
static function bool AddAdapter(class<NiceAbilitiesAdapter> newAdapter, optional LevelInfo level){
local int i;
if(newAdapter == none) return false;
for(i = 0;i < default.adapters.length;i ++) if(default.adapters[i] == newAdapter) return false;
newAdapter.default.level = level;
default.adapters[default.adapters.length] = newAdapter;
return true;
}
// If adapter wasn't even present also returns 'false'.
static function bool RemoveAdapter(class<NiceAbilitiesAdapter> adapter){
local int i;
if(adapter == none) return false;
for(i = 0;i < default.adapters.length;i ++){ if(default.adapters[i] == adapter){ default.adapters.Remove(i, 1); return true; }
}
return false;
}
static function CallAbilityActivated
( string abilityID, NicePlayerController relatedPlayer
){
local int i;
for(i = 0;i < default.adapters.length;i ++) default.adapters[i].static.AbilityActivated(abilityID, relatedPlayer);
}
static function CallAbilityAdded
( string abilityID, NicePlayerController relatedPlayer
){
local int i;
for(i = 0;i < default.adapters.length;i ++) default.adapters[i].static.AbilityAdded(abilityID, relatedPlayer);
}
static function CallAbilityRemoved
( string abilityID, NicePlayerController relatedPlayer
){
local int i;
for(i = 0;i < default.adapters.length;i ++) default.adapters[i].static.AbilityRemoved(abilityID, relatedPlayer);
}
static function CallModAbilityCooldown
( string abilityID, NicePlayerController relatedPlayer, out float cooldown
){
local int i;
for(i = 0;i < default.adapters.length;i ++){ default.adapters[i].static.ModAbilityCooldown( abilityID, relatedPlayer, cooldown);
}
}
defaultproperties
{
}

View File

@ -0,0 +1,137 @@
//==============================================================================
// NicePack / NiceAbilityManager
//==============================================================================
// Class that manager active abilities, introduced along with a NicePack.
// Can support at most 5 ('maxAbilitiesAmount') different abilities at once.
// NICETODO: refactor later
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceAbilityManager extends Actor;
var const int maxAbilitiesAmount;
// Defines a list of all possible ability's states
enum EAbilityState{
// Ability is ready to use
ASTATE_READY,
// Ability is being used
ASTATE_ACTIVE,
// Ability is on cooldown
ASTATE_COOLDOWN
};
// Describes all the necessary information about an ability
struct NiceAbilityDescription{
// Ability's ID, supposed to be unique per ability,
// but no checks are enforced yet
var string ID;
// Image to be used as an ability's icon
var Texture icon;
// Default cooldown duration
var float cooldownLength;
// Can ability be canceled once activated?
var bool canBeCancelled;
};
// Complete description of current status of an ability,
// including it's complete description.
struct NiceAbilityStatus{
// Complete description of ability in question
var NiceAbilityDescription description;
// Current cooldown value
var float cooldown;
// Current state of an ability
var EAbilityState myState;
};
var NiceAbilityStatus currentAbilities[5];
var int currentAbilitiesAmount;
// Refers to the player whose abilities we manage
var NicePlayerController relatedPlayer;
var const class<NiceAbilitiesEvents> events;
// Unfortunately this hackk is required to force replication of structure array
var int hackCounter;
replication{
reliable if(Role == ROLE_Authority) currentAbilities, currentAbilitiesAmount, hackCounter;
}
simulated function PostBeginPlay(){
relatedPlayer = NicePlayerController(owner);
}
function AddAbility(NiceAbilityDescription description){
local int i;
local NiceAbilityStatus newRecord;
if(currentAbilitiesAmount >= maxAbilitiesAmount) return;
for(i = 0;i < currentAbilitiesAmount;i ++) if(currentAbilities[i].description.ID ~= description.ID) return;
newRecord.description = description;
newRecord.cooldown = 0.0;
newRecord.myState = ASTATE_READY;
currentAbilities[currentAbilitiesAmount] = newRecord;
currentAbilitiesAmount += 1;
events.static.CallAbilityAdded(description.ID, relatedPlayer);
netUpdateTime = level.timeSeconds - 1;
}
function RemoveAbility(string abilityID){
local int i, j;
local bool wasRemoved;
j = 0;
for(i = 0;i < currentAbilitiesAmount;i ++){ if(currentAbilities[i].description.ID ~= abilityID){ wasRemoved = true; continue; } currentAbilities[j] = currentAbilities[i]; j += 1;
}
currentAbilitiesAmount = j;
if(wasRemoved) events.static.CallAbilityRemoved(abilityID, relatedPlayer);
netUpdateTime = level.timeSeconds - 1;
}
function ClearAbilities(){
currentAbilitiesAmount = 0;
netUpdateTime = level.timeSeconds - 1;
}
// Returns index of the ability with a given name.
// Returns '-1' if such ability doesn't exist.
simulated function int GetAbilityIndex(string abilityID){
local int i;
for(i = 0;i < currentAbilitiesAmount;i ++) if(currentAbilities[i].description.ID ~= abilityID) return i;
return -1;
}
simulated function bool IsAbilityActive(string abilityID){
local int index;
index = GetAbilityIndex(abilityID);
if(index < 0) return false;
return (currentAbilities[index].myState == ASTATE_ACTIVE);
}
// Sets ability to a proper state.
// Does nothing if ability is already in a specified state.
// Setting active ability to a ready state is only allowed
// if ability can be canceled.
// Updates cooldown to full length if new state is 'ASTATE_COOLDOWN'.
function SetAbilityState(int abilityIndex, EAbilityState newState){
local float cooldown;
local EAbilityState currentState;
if(abilityIndex < 0 || abilityIndex >= currentAbilitiesAmount) return;
currentState = currentAbilities[abilityIndex].myState;
if(currentState == newState) return;
if( currentState == ASTATE_ACTIVE && newState == ASTATE_READY && !currentAbilities[abilityIndex].description.canBeCancelled) return;
currentAbilities[abilityIndex].myState = newState;
if(newState == ASTATE_COOLDOWN){ cooldown = currentAbilities[abilityIndex].description.cooldownLength; events.static.CallModAbilityCooldown( currentAbilities[abilityIndex].description.ID, relatedPlayer, cooldown ); currentAbilities[abilityIndex].cooldown = cooldown;
}
hackCounter ++;
netUpdateTime = level.timeSeconds - 1;
// Fire off events
if(newState == ASTATE_ACTIVE){ events.static.CallAbilityActivated( currentAbilities[abilityIndex].description.ID, relatedPlayer );
}
}
// Changes ability's cooldown by a given amount.
// If this brings cooldown to zero or below -
// resets current ability to a 'ready' (ASTATE_READY) state.
function AddToCooldown(int abilityIndex, float delta){
if(abilityIndex < 0 || abilityIndex >= currentAbilitiesAmount) return;
if(currentAbilities[abilityIndex].myState != ASTATE_COOLDOWN) return;
currentAbilities[abilityIndex].cooldown += delta;
if(currentAbilities[abilityIndex].cooldown <= 0) SetAbilityState(abilityIndex, ASTATE_READY);
hackCounter ++;
}
function Tick(float deltaTime){
local int i;
if(Role != Role_AUTHORITY) return;
for(i = 0;i < currentAbilitiesAmount;i ++) AddToCooldown(i, -deltaTime);
}
defaultproperties
{ maxAbilitiesAmount=5 Events=Class'NicePack.NiceAbilitiesEvents' DrawType=DT_None
}

View File

@ -0,0 +1,8 @@
class NiceDamageTypeVetBerserker extends NiceWeaponDamageType
abstract;
static function AwardNiceDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount, int HL){
if(SRStatsBase(KFStatsAndAchievements) != none && SRStatsBase(KFStatsAndAchievements).Rep != none) SRStatsBase(KFStatsAndAchievements).Rep.ProgressCustomValue(Class'NiceVetBerserkerExp', Int(Float(Amount) * class'NicePack'.default.vetZerkDamageExpCost * getScale(HL)));
}
defaultproperties
{ HeadShotDamageMult=1.250000 bIsMeleeDamage=True DeathString="%o was beat down by %k." FemaleSuicide="%o beat herself down." MaleSuicide="%o beat himself down." bRagdollBullet=True bBulletHit=True PawnDamageEmitter=Class'ROEffects.ROBloodPuff' LowGoreDamageEmitter=Class'ROEffects.ROBloodPuffNoGore' LowDetailEmitter=Class'ROEffects.ROBloodPuffSmall' FlashFog=(X=600.000000) KDamageImpulse=2000.000000 KDeathVel=100.000000 KDeathUpKick=25.000000 VehicleDamageScaling=0.600000
}

View File

@ -0,0 +1,88 @@
class NiceVetBerserker extends NiceVeterancyTypes
abstract;
static function AddCustomStats(ClientPerkRepLink Other){
other.AddCustomValue(Class'NiceVetBerserkerExp');
}
static function int GetStatValueInt(ClientPerkRepLink StatOther, byte ReqNum){
return StatOther.GetCustomValueInt(Class'NiceVetBerserkerExp');
}
static function array<int> GetProgressArray(byte ReqNum, optional out int DoubleScalingBase){
return default.progressArray0;
}
static function int AddDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InDamage, class<DamageType> DmgType){
local float perkDamage;
local class<NiceWeaponPickup> pickupClass;
pickupClass = GetPickupFromDamageType(DmgType);
perkDamage = float(InDamage);
if(IsPerkedPickup(pickupClass)) perkDamage *= 2;
return perkDamage;
}
static function float GetFireSpeedModStatic(KFPlayerReplicationInfo KFPRI, class<Weapon> other){
local float bonus;
local class<NiceWeaponPickup> pickupClass;
local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer;
pickupClass = GetPickupFromWeapon(other);
bonus = 1.0;
nicePlayer = NicePlayerController(KFPRI.Owner);
if(IsPerkedPickup(pickupClass)) bonus *= 1.25;
nicePawn = NiceHumanPawn(nicePlayer.Pawn);
if(nicePlayer != none && nicePawn != none && HasSkill(nicePlayer, class'NiceSkillZerkFury') && IsPerkedPickup(pickupClass)){ if(nicePawn != none && nicePawn.invincibilityTimer > 0.0) bonus *= class'NiceSkillZerkFury'.default.attackSpeedBonus;
}
if(nicePlayer != none && nicePawn != none && nicePlayer.IsZedTimeActive() && IsPerkedPickup(pickupClass) && HasSkill(nicePlayer, class'NiceSkillZerkZEDAccelerate')) bonus /= (nicePawn.Level.TimeDilation / 1.1);
return bonus;
}
static function float GetMeleeMovementSpeedModifier(KFPlayerReplicationInfo KFPRI){
return 0.2;
}
static function float GetMovementSpeedModifier(KFPlayerReplicationInfo KFPRI, KFGameReplicationInfo KFGRI)
{
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(KFPRI.Owner);
if(nicePlayer != none && nicePlayer.IsZedTimeActive() && HasSkill(nicePlayer, class'NiceSkillZerkZEDAccelerate')) return 1.0 / fmin(1.0, (KFGRI.Level.TimeDilation / 1.1));
return 1.0;
}
static function float GetWeaponMovementSpeedBonus(KFPlayerReplicationInfo KFPRI, Weapon Weap){
local float bonus;
local NicePlayerController nicePlayer;
local NiceHumanPawn nicePawn;
bonus = 0.0;
nicePlayer = NicePlayerController(KFPRI.Owner);
if(nicePlayer != none) nicePawn = NiceHumanPawn(nicePlayer.Pawn);
if(nicePlayer != none && nicePawn != none && HasSkill(nicePlayer, class'NiceSkillZerkWhirlwind')){ if(nicePawn != none && nicePawn.invincibilityTimer > 0.0) bonus = 1.0;
}
return bonus;
}
static function bool CanBeGrabbed(KFPlayerReplicationInfo KFPRI, KFMonster Other){
return false;
}
// Set number times Zed Time can be extended
static function int ZedTimeExtensions(KFPlayerReplicationInfo KFPRI){
return 4;
}
static function float SlowingModifier(KFPlayerReplicationInfo KFPRI){
return 1.2;
}
static function int GetInvincibilityExtentions(KFPlayerReplicationInfo KFPRI){
return 3;
}
static function int GetInvincibilityDuration(KFPlayerReplicationInfo KFPRI){
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(KFPRI.Owner);
if( nicePlayer != none && HasSkill(nicePlayer, class'NiceSkillZerkColossus')){ return 3.0 + class'NiceSkillZerkColossus'.default.timeBonus;
}
return 3.0;
}
static function int GetInvincibilitySafeMisses(KFPlayerReplicationInfo KFPRI){
local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(KFPRI.Owner);
if( nicePlayer != none && HasSkill(nicePlayer, class'NiceSkillZerkUndead')){ return 1 + class'NiceSkillZerkUndead'.default.addedSafeMisses;
}
return 1;
}
static function string GetCustomLevelInfo(byte Level){
return default.CustomLevelInfo;
}
defaultproperties
{ bNewTypePerk=True SkillGroupA(0)=Class'NicePack.NiceSkillZerkWindCutter' SkillGroupA(1)=Class'NicePack.NiceSkillZerkWhirlwind' SkillGroupA(2)=Class'NicePack.NiceSkillZerkColossus' SkillGroupA(3)=Class'NicePack.NiceSkillZerkUndead' SkillGroupA(4)=Class'NicePack.NiceSkillZerkZEDAccelerate' SkillGroupB(0)=Class'NicePack.NiceSkillZerkCleave' SkillGroupB(1)=Class'NicePack.NiceSkillZerkFury' SkillGroupB(2)=Class'NicePack.NiceSkillZerkGunzerker' SkillGroupB(3)=Class'NicePack.NiceSkillZerkVorpalBlade' SkillGroupB(4)=Class'NicePack.NiceSkillZerkZEDUnbreakable' progressArray0(0)=100 progressArray0(1)=1000 progressArray0(2)=3000 progressArray0(3)=10000 progressArray0(4)=30000 progressArray0(5)=100000 progressArray0(6)=200000 DefaultDamageType=Class'NicePack.NiceDamageTypeVetBerserker' OnHUDIcons(0)=(PerkIcon=Texture'KillingFloorHUD.Perks.Perk_Berserker',StarIcon=Texture'KillingFloorHUD.HUD.Hud_Perk_Star',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(1)=(PerkIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Berserker_Gold',StarIcon=Texture'KillingFloor2HUD.Perk_Icons.Hud_Perk_Star_Gold',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(2)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Berserker_Green',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Green',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(3)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Berserker_Blue',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Blue',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(4)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Berserker_Purple',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Purple',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(5)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Berserker_Orange',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Orange',DrawColor=(B=255,G=255,R=255,A=255)) CustomLevelInfo="Level up by doing damage with perked weapons|100% extra melee damage|25% faster melee attacks|20% faster melee movement|Melee invincibility lasts 3 seconds|Melee invincibility doesn't reset on your first miss|Up to 4 Zed-Time Extensions|Can't be grabbed by clots|Can activate melee-invincibility with non-decapitating head-shots up to 3 times" PerkIndex=4 OnHUDIcon=Texture'KillingFloorHUD.Perks.Perk_Berserker' OnHUDGoldIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Berserker_Gold' VeterancyName="Berserker" Requirements(0)="Required experience for the next level: %x"
}

View File

@ -0,0 +1,4 @@
class NiceVetBerserkerExp extends SRCustomProgressInt;
defaultproperties
{ ProgressName="Berserker exp."
}

View File

@ -0,0 +1,5 @@
class NiceSkillZerkBrawler extends NiceSkill
abstract;
defaultproperties
{ SkillName="Brawler" SkillEffects="Clots can't grab you."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkCleave extends NiceSkill
abstract;
var float bonusDegrees;
defaultproperties
{ bonusDegrees=0.523599 SkillName="Cleave" SkillEffects="Add 30 degrees to wide attacks with melee weapons."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkColossus extends NiceSkill
abstract;
var float timeBonus;
defaultproperties
{ timeBonus=1.000000 SkillName="Colossus" SkillEffects="Invincibility period lasts 1 second longer."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkFury extends NiceSkill
abstract;
var float attackSpeedBonus;
defaultproperties
{ attackSpeedBonus=1.500000 SkillName="Fury" SkillEffects="Attack 50% faster during invincibility."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkGunzerker extends NiceSkill
abstract;
var float cooldown;
defaultproperties
{ cooldown=-2.000000 SkillName="Gunzerker" SkillEffects="You're able to activate melee-invincibility with non-melee headshots, but your misses are punished by a 2 second cooldown, during which you cannot activate invincibility."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkUndead extends NiceSkill
abstract;
var int addedSafeMisses;
defaultproperties
{ addedSafeMisses=1 SkillName="Undead" SkillEffects="Get additional safe melee-miss during invincibility period."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkVorpalBlade extends NiceSkill
abstract;
var float damageBonus;
defaultproperties
{ damageBonus=2.000000 SkillName="Vorpal blade" SkillEffects="Your head-shot deals double damage on your first invincibility extension against the zed."
}

View File

@ -0,0 +1,5 @@
class NiceSkillZerkWhirlwind extends NiceSkill
abstract;
defaultproperties
{ SkillName="Whirlwind" SkillEffects="Move twice as fast during invincibility."
}

View File

@ -0,0 +1,6 @@
class NiceSkillZerkWindCutter extends NiceSkill
abstract;
var float rangeBonus;
defaultproperties
{ rangeBonus=1.500000 SkillName="Wind cutter" SkillEffects="Increase your reach with melee-weapons by 50%."
}

View File

@ -0,0 +1,5 @@
class NiceSkillZerkZEDAccelerate extends NiceSkill
abstract;
defaultproperties
{ SkillName="Accelerate" SkillEffects="Move and attack at the same speed during zed-time."
}

View File

@ -0,0 +1,5 @@
class NiceSkillZerkZEDUnbreakable extends NiceSkill
abstract;
defaultproperties
{ SkillName="Unbreakable" SkillEffects="You resist all damage during zed time."
}

View File

@ -0,0 +1,14 @@
class NiceDamageTypeVetCommando extends NiceWeaponDamageType
abstract;
static function AwardKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed ){
if(Killed.IsA('ZombieStalker')) KFStatsAndAchievements.AddStalkerKill();
}
static function AwardDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount){
KFStatsAndAchievements.AddBullpupDamage(Amount);
}
static function AwardNiceDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount, int HL){
if(SRStatsBase(KFStatsAndAchievements) != none && SRStatsBase(KFStatsAndAchievements).Rep != none) SRStatsBase(KFStatsAndAchievements).Rep.ProgressCustomValue(Class'NiceVetCommandoExp', Int(Float(Amount) * class'NicePack'.default.vetCommandoDamageExpCost * getScale(HL)));
}
defaultproperties
{
}

View File

@ -0,0 +1,38 @@
class NiceVetCommando extends NiceVeterancyTypes
abstract;
static function AddCustomStats(ClientPerkRepLink Other){
other.AddCustomValue(Class'NiceVetCommandoExp');
}
static function int GetStatValueInt(ClientPerkRepLink StatOther, byte ReqNum){
return StatOther.GetCustomValueInt(Class'NiceVetCommandoExp');
}
static function array<int> GetProgressArray(byte ReqNum, optional out int DoubleScalingBase){
return default.progressArray0;
}
static function float GetHealthBarsDistanceMulti(KFPlayerReplicationInfo KFPRI){
if(KFPRI != none && SomeoneHasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillCommandoStrategist')) return class'NiceSkillCommandoStrategist'.default.visionRadius;
return 0.0;
}
static function float GetStalkerViewDistanceMulti(KFPlayerReplicationInfo KFPRI){
if(KFPRI != none && SomeoneHasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillCommandoStrategist')) return class'NiceSkillCommandoStrategist'.default.visionRadius;
return 0.0;
}
static function float GetMagCapacityMod(KFPlayerReplicationInfo KFPRI, KFWeapon Other){
local class<NiceWeaponPickup> pickupClass;
pickupClass = GetPickupFromWeapon(other.class);
if(IsPerkedPickup(pickupClass) && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillCommandoLargerMags')) return class'NiceSkillCommandoLargerMags'.default.sizeBonus;
return 1.0;
}
static function float GetReloadSpeedModifierStatic(KFPlayerReplicationInfo KFPRI, class<KFWeapon> Other){
return 1.3;
}
static function int ZedTimeExtensions(KFPlayerReplicationInfo KFPRI){
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillCommandoTactitian')) return class'NiceSkillCommandoTactitian'.default.bonusExt + 3;
return 3;
}
static function string GetCustomLevelInfo(byte Level){
return default.CustomLevelInfo;
}
defaultproperties
{ bNewTypePerk=True SkillGroupA(0)=Class'NicePack.NiceSkillCommandoTactitian' SkillGroupA(1)=Class'NicePack.NiceSkillCommandoCriticalFocus' SkillGroupA(2)=Class'NicePack.NiceSkillCommandoLargerMags' SkillGroupA(3)=Class'NicePack.NiceSkillCommandoPerfectExecution' SkillGroupA(4)=Class'NicePack.NiceSkillCommandoZEDProfessional' SkillGroupB(0)=Class'NicePack.NiceSkillCommandoStrategist' SkillGroupB(1)=Class'NicePack.NiceSkillCommandoTrashCleaner' SkillGroupB(2)=Class'NicePack.NiceSkillCommandoExplosivePower' SkillGroupB(3)=Class'NicePack.NiceSkillCommandoThinOut' SkillGroupB(4)=Class'NicePack.NiceSkillCommandoZEDEvisceration' progressArray0(0)=100 progressArray0(1)=1000 progressArray0(2)=3000 progressArray0(3)=10000 progressArray0(4)=30000 progressArray0(5)=100000 progressArray0(6)=200000 DefaultDamageType=Class'NicePack.NiceDamageTypeVetCommando' OnHUDIcons(0)=(PerkIcon=Texture'KillingFloorHUD.Perks.Perk_Commando',StarIcon=Texture'KillingFloorHUD.HUD.Hud_Perk_Star',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(1)=(PerkIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Commando_Gold',StarIcon=Texture'KillingFloor2HUD.Perk_Icons.Hud_Perk_Star_Gold',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(2)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Green',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Green',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(3)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Blue',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Blue',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(4)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Purple',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Purple',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(5)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Orange',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Orange',DrawColor=(B=255,G=255,R=255,A=255)) CustomLevelInfo="Level up by doing damage with perked weapons|30% faster reload with all weapons|You get three additional Zed-Time Extensions" PerkIndex=3 OnHUDIcon=Texture'KillingFloorHUD.Perks.Perk_Commando' OnHUDGoldIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Commando_Gold' VeterancyName="Commando" Requirements(0)="Required experience for the next level: %x"
}

View File

@ -0,0 +1,4 @@
class NiceVetCommandoExp extends SRCustomProgressInt;
defaultproperties
{ ProgressName="Commando exp."
}

View File

@ -0,0 +1,28 @@
class NiceSkillCommandoCriticalFocus extends NiceSkill
abstract;
var float cooldown;
var float healthBoundary;
function static SkillSelected(NicePlayerController nicePlayer){
local NicePack niceMutator;
super.SkillSelected(nicePlayer);
niceMutator = class'NicePack'.static.Myself(nicePlayer.Level);
if(niceMutator == none || niceMutator.Role == Role_AUTHORITY) return;
niceMutator.AddCounter("npCommandoCriticalFocus", Texture'NicePackT.HudCounter.commandoCounter', false, default.class);
}
function static SkillDeSelected(NicePlayerController nicePlayer){
local NicePack niceMutator;
super.SkillDeSelected(nicePlayer);
niceMutator = class'NicePack'.static.Myself(nicePlayer.Level);
if(niceMutator == none || niceMutator.Role == Role_AUTHORITY) return;
niceMutator.RemoveCounter("npCommandoCriticalFocus");
}
function static int UpdateCounterValue(string counterName, NicePlayerController nicePlayer){
local NiceHumanPawn nicePawn;
if(nicePlayer == none || counterName != "npCommandoCriticalFocus") return 0;
nicePawn = NiceHumanPawn(nicePlayer.pawn);
if(nicePawn == none) return 0;
return Ceil(nicePawn.forcedZedTimeCountDown);
}
defaultproperties
{ cooldown=30.000000 healthBoundary=50.000000 SkillName="Critical focus"
}

View File

@ -0,0 +1,6 @@
class NiceSkillCommandoExplosivePower extends NiceSkill
abstract;
var float dmgMod;
defaultproperties
{ dmgMod=1.200000 SkillName="Explosive power" SkillEffects="Burst fire deals 20% more damage and has reduced delay between shots."
}

View File

@ -0,0 +1,6 @@
class NiceSkillCommandoLargerMags extends NiceSkill
abstract;
var float sizeBonus;
defaultproperties
{ sizeBonus=1.500000 SkillName="Larger mags" SkillEffects="50% larger assault rifles' magazines."
}

View File

@ -0,0 +1,5 @@
class NiceSkillCommandoPerfectExecution extends NiceSkill
abstract;
defaultproperties
{ SkillName="Perfect execution" SkillEffects="Raging scrake or fleshpound activates zed-time."
}

View File

@ -0,0 +1,6 @@
class NiceSkillCommandoStrategist extends NiceSkill
abstract;
var float visionRadius; // 1.0 ~ 16m
defaultproperties
{ visionRadius=1.000000 bBroadcast=True SkillName="Strategist" SkillEffects="You and your teammates can see enemies' health and invisible zeds from 16 meters."
}

View File

@ -0,0 +1,6 @@
class NiceSkillCommandoTactitian extends NiceSkill
abstract;
var int bonusExt;
defaultproperties
{ bonusExt=2 SkillName="Tactician" SkillEffects="Gain two additional zed-time extensions."
}

View File

@ -0,0 +1,7 @@
class NiceSkillCommandoThinOut extends NiceSkill
abstract;
var float damageMult;
var float maxDistance;
defaultproperties
{ damageMult=2.000000 MaxDistance=800.000000 SkillName="Thin out" SkillEffects="Deal double damage against non-trash zeds, when there's either a huge zed or another zed of the same type within 16 meters of you."
}

View File

@ -0,0 +1,6 @@
class NiceSkillCommandoTrashCleaner extends NiceSkill
abstract;
var float decapitationMultiLimit;
defaultproperties
{ decapitationMultiLimit=0.600000 SkillName="Trash cleaner" SkillEffects="Get finisher property on your shots against low-health zeds, but your weapons leave more decapitated zeds behind."
}

View File

@ -0,0 +1,5 @@
class NiceSkillCommandoZEDEvisceration extends NiceSkill
abstract;
defaultproperties
{ SkillName="Evisceration" SkillEffects="During zed-time both 'Trash cleaner' and 'Thin out' skills are active."
}

View File

@ -0,0 +1,5 @@
class NiceSkillCommandoZEDProfessional extends NiceSkill
abstract;
defaultproperties
{ SkillName="Professionalism" SkillEffects="Your reloads aren't slowed down during zed-time."
}

View File

@ -0,0 +1,5 @@
class NiceDamTypeDemoBlunt extends NiceDamageTypeVetDemolitions
abstract;
defaultproperties
{ HeadShotDamageMult=2.000000 bSniperWeapon=True DeathString="%k killed %o (LAW Impact)." FemaleSuicide="%o shot herself in the foot." MaleSuicide="%o shot himself in the foot." bRagdollBullet=True bBulletHit=True FlashFog=(X=600.000000) KDamageImpulse=5000.000000 KDeathVel=200.000000 KDeathUpKick=50.000000 VehicleDamageScaling=0.700000
}

View File

@ -0,0 +1,9 @@
class NiceDamTypeDemoExplosion extends NiceDamageTypeVetDemolitions;
static function GetHitEffects(out class<xEmitter> HitEffects[4], int VictimHealth){
HitEffects[0] = class'HitSmoke';
if(VictimHealth <= 0) HitEffects[1] = class'KFHitFlame';
else if(FRand() < 0.8) HitEffects[1] = class'KFHitFlame';
}
defaultproperties
{ stunMultiplier=0.600000 bIsExplosive=True DeathString="%o filled %k's body with shrapnel." FemaleSuicide="%o blew up." MaleSuicide="%o blew up." bLocationalHit=False bThrowRagdoll=True bExtraMomentumZ=True DamageThreshold=1 DeathOverlayMaterial=Combiner'Effects_Tex.GoreDecals.PlayerDeathOverlay' DeathOverlayTime=999.000000 KDamageImpulse=3000.000000 KDeathVel=300.000000 KDeathUpKick=250.000000 HumanObliterationThreshhold=150
}

View File

@ -0,0 +1,4 @@
class NiceDamTypeDemoSafeExplosion extends NiceDamTypeDemoExplosion;
defaultproperties
{
}

View File

@ -0,0 +1,8 @@
class NiceDamageTypeVetDemolitions extends NiceWeaponDamageType
abstract;
static function AwardNiceDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount, int HL){
if(SRStatsBase(KFStatsAndAchievements) != none && SRStatsBase(KFStatsAndAchievements).Rep != none) SRStatsBase(KFStatsAndAchievements).Rep.ProgressCustomValue(Class'NiceVetDemolitionsExp', Int(Float(Amount) * class'NicePack'.default.vetDemoDamageExpCost * getScale(HL)));
}
defaultproperties
{
}

View File

@ -0,0 +1,66 @@
class NiceVetDemolitions extends NiceVeterancyTypes
abstract;
static function AddCustomStats(ClientPerkRepLink Other){
other.AddCustomValue(Class'NiceVetDemolitionsExp');
}
static function int GetStatValueInt(ClientPerkRepLink StatOther, byte ReqNum){
return StatOther.GetCustomValueInt(Class'NiceVetDemolitionsExp');
}
static function array<int> GetProgressArray(byte ReqNum, optional out int DoubleScalingBase){
return default.progressArray0;
}
static function int ReduceDamage(KFPlayerReplicationInfo KFPRI, KFPawn Injured, Pawn Instigator, int InDamage, class<DamageType> DmgType){
local NicePlayerController nicePlayer;
if(class<NiceDamTypeDemoSafeExplosion>(DmgType) != none) return 0;
nicePlayer = NicePlayerController(KFPRI.Owner);
if(nicePlayer != none && Instigator == nicePlayer.pawn && nicePlayer.IsZedTimeActive() && HasSkill(nicePlayer, class'NiceSkillDemoZEDDuckAndCover')) return 0.0;
if((class<KFWeaponDamageType>(DmgType) != none && class<KFWeaponDamageType>(DmgType).default.bIsExplosive)) return float(InDamage) * 0.5;
return InDamage;
}
static function float AddExtraAmmoFor(KFPlayerReplicationInfo KFPRI, Class<Ammunition> AmmoType){
local float bonusNades, bonusPipes;
// Default bonus
bonusNades = 5;
bonusPipes = 6;
if(AmmoType == class'FragAmmo') return 1.0 + 0.2 * bonusNades;
if(ClassIsChildOf(AmmoType, class'PipeBombAmmo')) return 1.0 + 0.5 * bonusPipes;
return 1.0;
}
static function int AddDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InDamage, class<DamageType> DmgType){
local float perkDamage;
local class<NiceWeaponPickup> pickupClass;
pickupClass = GetPickupFromDamageType(DmgType);
perkDamage = float(InDamage);
if(DmgType == class'NicePack.NiceDamTypeDemoExplosion') return 1.6 * perkDamage;
if(IsPerkedPickup(pickupClass)) perkDamage *= 1.25;
else if( pickupClass != none && pickupClass.default.weight <= class'NiceSkillDemoOffperk'.default.weightBound && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillDemoOffperk') ) perkDamage *= class'NiceSkillDemoOffperk'.default.damageBonus;
if( KFPRI != none && class<NiceDamTypeDemoBlunt>(DmgType) != none && SomeoneHasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillDemoOnperk') ) perkDamage *= class'NiceSkillDemoOnperk'.default.damageBonus;
return perkDamage;
}
static function float GetReloadSpeedModifierStatic(KFPlayerReplicationInfo KFPRI, class<KFWeapon> other){
local NiceHumanPawn nicePawn;
local class<NiceWeaponPickup> pickupClass;
// Pistols reload
if( other != none && other.default.weight <= class'NiceSkillDemoOffperk'.default.weightBound && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillDemoOffperk') ) return class'NiceSkillDemoOffperk'.default.reloadBonus;
// Maniac reload
pickupClass = GetPickupFromWeapon(other);
if(KFPRI != none && PlayerController(KFPRI.Owner) != none) nicePawn = NiceHumanPawn(PlayerController(KFPRI.Owner).Pawn);
if(nicePawn != none && nicePawn.maniacTimeout >= 0.0 && IsPerkedPickup(pickupClass)) return class'NiceSkillDemoManiac'.default.reloadSpeedup;
return 1.0;
}
static function float stunDurationMult(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, class<NiceWeaponDamageType> DmgType){
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillDemoConcussion')) return class'NiceSkillDemoConcussion'.default.durationMult;
return 1.0;
}
static function int AddStunScore(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InStunScore, class<NiceWeaponDamageType> DmgType){
return int(float(InStunScore) * 1.5);
}
static function int AddFlinchScore(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InFlinchScore, class<NiceWeaponDamageType> DmgType){
return int(float(InFlinchScore) * 1.5);
}
static function string GetCustomLevelInfo(byte Level){
return default.CustomLevelInfo;
}
defaultproperties
{ bNewTypePerk=True SkillGroupA(0)=Class'NicePack.NiceSkillDemoOnperk' SkillGroupA(1)=Class'NicePack.NiceSkillDemoDirectApproach' SkillGroupA(2)=Class'NicePack.NiceSkillDemoConcussion' SkillGroupA(3)=Class'NicePack.NiceSkillDemoAPShot' SkillGroupA(4)=Class'NicePack.NiceSkillDemoZEDDuckAndCover' SkillGroupB(0)=Class'NicePack.NiceSkillDemoOffperk' SkillGroupB(1)=Class'NicePack.NiceSkillDemoVolatile' SkillGroupB(2)=Class'NicePack.NiceSkillDemoReactiveArmor' SkillGroupB(3)=Class'NicePack.NiceSkillDemoManiac' SkillGroupB(4)=Class'NicePack.NiceSkillDemoZEDFullBlast' progressArray0(0)=100 progressArray0(1)=1000 progressArray0(2)=3000 progressArray0(3)=10000 progressArray0(4)=30000 progressArray0(5)=100000 progressArray0(6)=200000 DefaultDamageType=Class'NicePack.NiceDamageTypeVetDemolitions' OnHUDIcons(0)=(PerkIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Demolition',StarIcon=Texture'KillingFloorHUD.HUD.Hud_Perk_Star',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(1)=(PerkIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Demolition_Gold',StarIcon=Texture'KillingFloor2HUD.Perk_Icons.Hud_Perk_Star_Gold',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(2)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Demolition_Green',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Green',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(3)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Demolition_Blue',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Blue',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(4)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Demolition_Purple',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Purple',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(5)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Demolition_Orange',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Orange',DrawColor=(B=255,G=255,R=255,A=255)) CustomLevelInfo="Level up by doing damage with perked weapons|25% extra explosives damage|50% better stun and flinch ability for all weapons|50% resistance to explosives|+5 grenades|+6 pipe bombs" PerkIndex=6 OnHUDIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Demolition' OnHUDGoldIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Demolition_Gold' VeterancyName="Demolitions" Requirements(0)="Required experience for the next level: %x"
}

View File

@ -0,0 +1,4 @@
class NiceVetDemolitionsExp extends SRCustomProgressInt;
defaultproperties
{ ProgressName="Demolitions exp."
}

View File

@ -0,0 +1,7 @@
class NiceSkillDemoAPShot extends NiceSkill
abstract;
var float minCos;
var float damageRatio;
defaultproperties
{ minCos=0.707000 damageRatio=1.000000 SkillName="AP shot" SkillEffects="Deal full blast damage behind the target you've hit."
}

View File

@ -0,0 +1,6 @@
class NiceSkillDemoConcussion extends NiceSkill
abstract;
var float durationMult;
defaultproperties
{ durationMult=2.000000 SkillName="Concussion" SkillEffects="You stun zeds for twice longer time than usual."
}

View File

@ -0,0 +1,5 @@
class NiceSkillDemoDirectApproach extends NiceSkill
abstract;
defaultproperties
{ SkillName="Direct approach" SkillEffects="Your explosives will first hit target zed as a blunt before exploding."
}

View File

@ -0,0 +1,28 @@
class NiceSkillDemoManiac extends NiceSkill
abstract;
var float reloadBoostTime;
var float reloadSpeedup;
function static SkillSelected(NicePlayerController nicePlayer){
local NicePack niceMutator;
super.SkillSelected(nicePlayer);
niceMutator = class'NicePack'.static.Myself(nicePlayer.Level);
if(niceMutator == none || niceMutator.Role == Role_AUTHORITY) return;
niceMutator.AddCounter("npDemoManiac", Texture'NicePackT.HudCounter.demo', false, default.class);
}
function static SkillDeSelected(NicePlayerController nicePlayer){
local NicePack niceMutator;
super.SkillDeSelected(nicePlayer);
niceMutator = class'NicePack'.static.Myself(nicePlayer.Level);
if(niceMutator == none || niceMutator.Role == Role_AUTHORITY) return;
niceMutator.RemoveCounter("npDemoManiac");
}
function static int UpdateCounterValue(string counterName, NicePlayerController nicePlayer){
local NiceHumanPawn nicePawn;
if(nicePlayer == none || counterName != "npDemoManiac") return 0;
nicePawn = NiceHumanPawn(nicePlayer.pawn);
if(nicePawn == none || nicePawn.maniacTimeout <= 0.0) return 0;
return Ceil(nicePawn.maniacTimeout);
}
defaultproperties
{ reloadBoostTime=5.000000 reloadSpeedup=1.500000 SkillName="Maniac" SkillEffects="Reload 50% faster for 5 seconds after killing something."
}

View File

@ -0,0 +1,8 @@
class NiceSkillDemoOffperk extends NiceSkill
abstract;
var float damageBonus;
var float reloadBonus;
var int weightBound;
defaultproperties
{ damageBonus=1.250000 ReloadBonus=1.250000 weightBound=4 SkillName="Offperk" SkillEffects="Reload light weapons (less than 5 pounds) 25% faster and do 25% more damage with them."
}

View File

@ -0,0 +1,7 @@
class NiceSkillDemoOnperk extends NiceSkill
abstract;
var float damageBonus;
var float speedBonus;
defaultproperties
{ damageBonus=1.200000 speedBonus=1.500000 bBroadcast=True SkillName="Onperk" SkillEffects="Deal 20% more damage with your blunts and make your perk weapon's projectiles fly 50% faster."
}

View File

@ -0,0 +1,10 @@
class NiceSkillDemoReactiveArmor extends NiceSkill
abstract;
var float baseDamage;
var float perNadeDamage;
var float explRadius;
var float explExponent;
var float explMomentum;
defaultproperties
{ BaseDamage=3000.000000 explRadius=1000.000000 explExponent=1.000000 explMomentum=150000.000000 SkillName="Reactive armor" SkillEffects="Once per wave your death will be prevented, while zeds all around you will be blown to bits."
}

View File

@ -0,0 +1,8 @@
class NiceSkillDemoVolatile extends NiceSkill
abstract;
var float safeDistanceMult;
var float explRangeMult;
var float falloffMult;
defaultproperties
{ safeDistanceMult=0.500000 explRangeMult=1.000000 falloffMult=0.500000 SkillName="Volatile" SkillEffects="Safe range for your explosives is halved and explosion damage experiences smaller fall off."
}

View File

@ -0,0 +1,5 @@
class NiceSkillDemoZEDDuckAndCover extends NiceSkill
abstract;
defaultproperties
{ SkillName="Duck and cover" SkillEffects="During zed time you can't deal yourself any damage."
}

View File

@ -0,0 +1,6 @@
class NiceSkillDemoZEDFullBlast extends NiceSkill
abstract;
var float explRadiusMult;
defaultproperties
{ explRadiusMult=1.350000 SkillName="Full blast" SkillEffects="During zed time your explosions have 35% larger radius and their damage doesn't suffer from a fall off."
}

View File

@ -0,0 +1,10 @@
class NiceDamageTypeVetEnforcer extends NiceWeaponDamageType
abstract;
static function AwardNiceDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount, int HL){
if(SRStatsBase(KFStatsAndAchievements) != none && SRStatsBase(KFStatsAndAchievements).Rep != none) SRStatsBase(KFStatsAndAchievements).Rep.ProgressCustomValue(Class'NiceVetSupportExp', Int(Float(Amount) * class'NicePack'.default.vetSupportDamageExpCost * getScale(HL)));
}
defaultproperties
{ badDecapMod=1.000000 bIsProjectile=True HeadShotDamageMult=1.500000
}

View File

@ -0,0 +1,7 @@
class NiceDamageTypeVetEnforcerBullets extends NiceDamageTypeVetEnforcer
abstract;
defaultproperties
{
badDecapMod=0.2500000 goodDecapMod=0.500000 bodyDestructionMult=1.000000 HeadShotDamageMult=1.000000
}

View File

@ -0,0 +1,118 @@
class NiceVetEnforcer extends NiceVeterancyTypes
abstract;
static function AddCustomStats(ClientPerkRepLink Other){
Other.AddCustomValue(Class'NiceVetSupportExp');
}
static function int GetStatValueInt(ClientPerkRepLink StatOther, byte ReqNum){
return StatOther.GetCustomValueInt(Class'NiceVetSupportExp');
}
static function array<int> GetProgressArray(byte ReqNum, optional out int DoubleScalingBase){
return default.progressArray0;
}
// Other bonuses
static function float GetPenetrationDamageMulti(KFPlayerReplicationInfo KFPRI, float DefaultPenDamageReduction, class<NiceWeaponDamageType> fireIntance){
local float bonusReduction;
local float PenDamageInverse;
bonusReduction = 0.0;
if(class<NiceDamageTypeVetEnforcerBullets>(fireIntance) != none)
return DefaultPenDamageReduction;
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillSupportStubbornness')) bonusReduction = class'NiceSkillSupportStubbornness'.default.penLossRed;
PenDamageInverse = (1.0 - FMax(0, DefaultPenDamageReduction));
return DefaultPenDamageReduction + PenDamageInverse * (0.6 + 0.4 * bonusReduction); // 60% better penetrations + bonus
}
static function int AddStunScore(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InStunScore, class<NiceWeaponDamageType> DmgType){
local class<NiceWeaponPickup> pickupClass;
pickupClass = GetPickupFromDamageType(DmgType);
if(KFPRI != none && IsPerkedPickup(pickupClass) && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillEnforcerBombard')) return InStunScore * class'NiceSkillEnforcerBombard'.default.stunMult;
return InStunScore;
}
static function class<Grenade> GetNadeType(KFPlayerReplicationInfo KFPRI){
/*if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillSupportCautious')) return class'NicePack.NiceDelayedNade';
return class'NicePack.NiceNailNade';*/
return class'NicePack.NiceCryoNade';
}
static function int ReduceDamage(KFPlayerReplicationInfo KFPRI, KFPawn Injured, Pawn Instigator, int InDamage, class<DamageType> DmgType){
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillEnforcerDetermination') && Injured.Health < class'NiceSkillEnforcerDetermination'.default.healthBound)
InDamage *= (1 - class'NiceSkillEnforcerDetermination'.default.addedResist);
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillEnforcerUnshakable'))
InDamage *= (1 - class'NiceSkillEnforcerUnshakable'.default.skillResist);
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillHeavyCoating') && Injured.ShieldStrength > 0){
if( class<KFWeaponDamageType>(DmgType) != none
&& ((class<KFWeaponDamageType>(DmgType).default.bDealBurningDamage && KFMonster(Instigator) != none)
|| DmgType == class'NiceZombieTeslaHusk'.default.MyDamageType) )
InDamage *= (1 - class'NiceSkillHeavyCoating'.default.huskResist);
}
return InDamage;
}
static function float GetFireSpeedModStatic(KFPlayerReplicationInfo KFPRI, class<Weapon> other){
local float fireSpeed;
local NicePlayerController nicePlayer;
local class<NiceWeaponPickup> pickupClass;
pickupClass = GetPickupFromWeapon(other);
if(KFPRI.Owner == none)
return 1.0;
if(IsPerkedPickup(pickupClass) && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillHeavyOverclocking'))
fireSpeed = class'NiceSkillHeavyOverclocking'.default.fireSpeedMult;
else
fireSpeed = 1.0;
nicePlayer = NicePlayerController(KFPRI.Owner);
/*if(nicePlayer != none && HasSkill(nicePlayer, class'NiceSkillEnforcerZEDBarrage'))
fireSpeed /= (KFPRI.Owner.Level.TimeDilation / 1.1);*/
return fireSpeed;
}
static function float ModifyRecoilSpread(KFPlayerReplicationInfo KFPRI, WeaponFire other, out float Recoil){
local class<NiceWeaponPickup> pickupClass;
pickupClass = GetPickupFromWeaponFire(other);
if(IsPerkedPickup(pickupClass) && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillHeavyOverclocking'))
Recoil = class'NiceSkillHeavyOverclocking'.default.fireSpeedMult;
else
Recoil = 1.0;
return Recoil;
}
/*static function float GetMagCapacityModStatic(KFPlayerReplicationInfo KFPRI, class<KFWeapon> other){
local class<NiceWeapon> niceWeap;
niceWeap = class<NiceWeapon>(other);
if(niceWeap != none && niceWeap.default.reloadType == RTYPE_MAG)
return 1.5;
if(other == class'NicePack.NiceM41AAssaultRifle' || other == class'NicePack.NiceChainGun' || other == class'NicePack.NiceStinger' )
return 1.5;
return 1.0;
}*/
static function float GetMovementSpeedModifier(KFPlayerReplicationInfo KFPRI, KFGameReplicationInfo KFGRI){
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillEnforcerUnstoppable'))
return class'NiceSkillEnforcerUnstoppable'.default.speedMult;
return 1.0;
}
static function bool CanBePulled(KFPlayerReplicationInfo KFPRI){
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillEnforcerUnstoppable'))
return false;
return super.CanBePulled(KFPRI);
}
static function float SlowingModifier(KFPlayerReplicationInfo KFPRI){
if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillEnforcerUnstoppable'))
return 0.0;
return 1.0;
}
static function string GetCustomLevelInfo(byte Level){
return default.CustomLevelInfo;
}
defaultproperties
{ bNewTypePerk=True
SkillGroupA(0)=Class'NicePack.NiceSkillEnforcerUnstoppable' SkillGroupA(1)=Class'NicePack.NiceSkillEnforcerBombard' SkillGroupA(2)=Class'NicePack.NiceSkillEnforcerFullCounter' SkillGroupA(4)=Class'NicePack.NiceSkillEnforcerZEDBarrage'
SkillGroupB(0)=Class'NicePack.NiceSkillEnforcerUnshakable' SkillGroupB(1)=Class'NicePack.NiceSkillEnforcerMultitasker' SkillGroupB(2)=Class'NicePack.NiceSkillEnforcerDetermination' SkillGroupB(4)=Class'NicePack.NiceSkillEnforcerZEDJuggernaut' progressArray0(0)=100 progressArray0(1)=1000 progressArray0(2)=3000 progressArray0(3)=10000 progressArray0(4)=30000 progressArray0(5)=100000 progressArray0(6)=200000 DefaultDamageType=Class'NicePack.NiceDamageTypeVetEnforcer' OnHUDIcons(0)=(PerkIcon=Texture'KillingFloorHUD.Perks.Perk_Support',StarIcon=Texture'KillingFloorHUD.HUD.Hud_Perk_Star',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(1)=(PerkIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Support_Gold',StarIcon=Texture'KillingFloor2HUD.Perk_Icons.Hud_Perk_Star_Gold',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(2)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Support_Green',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Green',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(3)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Support_Blue',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Blue',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(4)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Support_Purple',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Purple',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(5)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Support_Orange',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Orange',DrawColor=(B=255,G=255,R=255,A=255)) CustomLevelInfo="Level up by doing damage with perked weapons|60% better penetration with all weapons" PerkIndex=1 OnHUDIcon=Texture'KillingFloorHUD.Perks.Perk_Support' OnHUDGoldIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Support_Gold' VeterancyName="Enforcer" Requirements(0)="Required experience for the next level: %x"
}

View File

@ -0,0 +1,4 @@
class NiceVetSupportExp extends SRCustomProgressInt;
defaultproperties
{ ProgressName="Enforcer exp."
}

View File

@ -0,0 +1,7 @@
class NiceSkillEnforcerBombard extends NiceSkill
abstract;
var float stunMult;
var float spreadMult;
defaultproperties
{ stunMult=3.000000 spreadMult=0.500000 SkillName="Bombard" SkillEffects="Your perked weapons are 3 times as good at stunning."
}

View File

@ -0,0 +1,6 @@
class NiceSkillEnforcerMultitasker extends NiceSkill
abstract;
var float reloadSlowDown;
defaultproperties
{ reloadSlowDown=5.000000 SkillName="Multitasker" SkillEffects="Reload holstered weapons at five times as much time."
}

View File

@ -0,0 +1,5 @@
class NiceSkillSupportAntiZed extends NiceSkill
abstract;
defaultproperties
{ SkillName="Anti-zed rounds" SkillEffects="When shotgun pellets pass screaming siren, they gain x4 damage boost."
}

View File

@ -0,0 +1,5 @@
class NiceSkillSupportArmory extends NiceSkill
abstract;
defaultproperties
{ bBroadcast=True SkillName="Armory" SkillEffects="Once per wave your team-mates will receive armored jacket when they run out of armor."
}

View File

@ -0,0 +1,6 @@
class NiceSkillSupportBigGameHunter extends NiceSkillGenAmmo
abstract;
var float damageBonus;
defaultproperties
{ damageBonus=1.600000 SkillName="Big-game hunter" SkillEffects="Gain 60% damage bonus with grenades, but carry 5 grenades less."
}

View File

@ -0,0 +1,5 @@
class NiceSkillSupportCautious extends NiceSkill
abstract;
defaultproperties
{ SkillName="Cautious" SkillEffects="Your grenades won't explode if you're too close to them."
}

View File

@ -0,0 +1,18 @@
class NiceSkillSupportDiversity extends NiceSkill
abstract;
var int bonusWeight;
static function UpdateWeight(NicePlayerController nicePlayer){
local NiceHumanPawn nicePawn;
if(nicePawn == none || nicePawn.KFPRI == none) return;
nicePawn.maxCarryWeight = nicePawn.default.maxCarryWeight;
if(nicePawn.KFPRI.clientVeteranSkill != none) nicePawn.maxCarryWeight += nicePawn.KFPRI.clientVeteranSkill.static.AddCarryMaxWeight(nicePawn.KFPRI);
}
function static SkillSelected(NicePlayerController nicePlayer){
UpdateWeight(nicePlayer);
}
function static SkillDeSelected(NicePlayerController nicePlayer){
UpdateWeight(nicePlayer);
}
defaultproperties
{ bonusWeight=5 SkillName="Diversity" SkillEffects="Gain +5 weight slots."
}

View File

@ -0,0 +1,7 @@
class NiceSkillSupportGraze extends NiceSkill
abstract;
var float hsBonusZoneMult;
var float grazeDamageMult;
defaultproperties
{ hsBonusZoneMult=1.500000 grazeDamageMult=0.750000 SkillName="Graze" SkillEffects="Your perked projectile can hit zeds' extended head zone for 75% of damage even if they miss the normal one."
}

View File

@ -0,0 +1,7 @@
class NiceSkillSupportObsessive extends NiceSkill
abstract;
var float reloadLevel;
var float reloadBonus;
defaultproperties
{ reloadLevel=0.650000 ReloadBonus=1.500000 SkillName="Obsessive" SkillEffects="Reload 50% faster when you lack at most 35% of bullets in the magazine."
}

View File

@ -0,0 +1,5 @@
class NiceSkillSupportSlugs extends NiceSkill
abstract;
defaultproperties
{ SkillName="Slugs" SkillEffects="Pellets shots replaced by slugs on shotguns."
}

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