Мутаторы и UnrealScript

Автовыкидывание оружия при несовпадении условий

Мутатор выкидывания оружия, если игрок не отвечает определённым критериям.
Например, выкидывание оружия чужого перка или выкидывание спец пушек, для которых надо обладать определённым уровнем и/или перка.
Оружие выкидывается перед игроком на определённом расстоянии.

Карточка катаны у Торговца Катана в меню Торговца.

WeaponInfoList=(Perk="SRVetBerserker",Level=4,Weapon="KFMod.Katana") - элемент основного массива
Weapon - код пушки (полный - пакет.оружие)
Perk -  перк обладателю которого позволено владеть данной пушкой (если написать Perk="", то важен только уровень - перк любой)
Level - уровень начиная с которого можно владеть оружием

То есть если мы хотим, чтобы катана у всех перков кроме берсеркера 4+ уровня выпадала - пишем то, что написано выше
Если мы хотим чтобы все перки до 6 выкидывали катану - пишем
WeaponInfoList=(Perk="",Level=6,Weapon="KFMod.Katana")
Если же мы хотим, чтобы катаной могли владеть берс начиная с 4 уровня и медик начиная с 8 уровня, то создаём ещё один элемента массива:
WeaponInfoList=(Perk="SRVetFieldMedic",Level=8,Weapon="KFMod.Katana")
При такой настройке катана будет у 4+ берса и 8+ медика, у остальных она будет выпадать

Ну вроде самое сложное отписал. Если что непонятно - спрашивайте в комментариях.
Остальные настройки:

ExceptionList=76561198044444444  - массив игроков на которых мутатор не действует
bAdminInExceptionList=false - принадлежат ли админы к исключениям? если true, то на всех кто сейчас находится под админкой мутатор не действует
TimerPeriod=2.000000 - период таймера в секундах, который осуществляет проверку легитимности)
bDestroy=True - некоторые пушки нельзя выкинуть, если значение этого параметра true - значит такие пушки просто будут уничтожаться
ThrowDistance=100 - расстояние на которое выбрасываются пушки впереди игрока
bSendInfoMessage=True - пишем ли мы сообщение игроку о выбрасывании пушки
MSG_Drop=Your perk and/or level is not good enough to possess - само сообщение. в конце данного сообщения автоматически добавляется название пушки (Weapon.ItemName)
class DropWeaponsMut extends Mutator config(DropWeaponsMut);

// Мутатор выкидывает упомянутое в ini оружие, если не выполнены условия по уровню и/или перку.
struct WeaponInfoStruct
{
    var() globalconfig string Perk;
    var() globalconfig int Level;
    var() globalconfig string Weapon;
};

var() globalconfig array<WeaponInfoStruct> WeaponInfoList;
var() globalconfig array<string> ExceptionList;
var() globalconfig bool bAdminInExceptionList;
var() globalconfig float TimerPeriod;
var() globalconfig bool bDestroy;
var() globalconfig int ThrowDistance;
var() globalconfig bool bSendInfoMessage;
var() globalconfig string MSG_Drop;

function PostBeginPlay()
{
    SaveConfig();
    SetTimer(TimerPeriod, true);
}

function Timer()
{
    local Controller C;

    for (C = Level.ControllerList; C != None; C = C.NextController)
    {
        if (C.IsA('PlayerController') && C.Pawn != None)
            ModifyPawn(C.Pawn);
    }
}

// Клиент: не оставить игрока без оружия после выброса.
simulated function Tick(float Delta)
{
    local PlayerController PC;

    PC = Level.GetLocalPlayerController();
    if (PC != None && PC.Pawn != None && PC.Pawn.Weapon == None)
        PC.SwitchToBestWeapon();
}

function ModifyPawn(Pawn Other)
{
    local Inventory Inv;

    if (Other == None || Other.Inventory == None)
        return;
    for (Inv = Other.Inventory; Inv != None; Inv = Inv.Inventory)
    {
        if (InDropList(Inv, Other) && !InExceptionList(Other.Controller))
            DropOrDestroy(Inv, Other);
    }
}

function bool InDropList(Inventory Inv, Pawn Other)
{
    local int i;
    local int cLevel;
    local string Veterancy;
    local int InList, ReturnTrue;
    local KFPlayerReplicationInfo KFPRI;

    KFPRI = KFPlayerReplicationInfo(Other.PlayerReplicationInfo);
    if (KFPRI != None)
    {
        cLevel = KFPRI.ClientVeteranSkillLevel;
        Veterancy = string(KFPRI.ClientVeteranSkill.Name);
    }
    for (i = 0; i < WeaponInfoList.Length; i++)
    {
        if (string(Inv.Class) ~= WeaponInfoList[i].Weapon)
        {
            InList++;
            if (
                (WeaponInfoList[i].Perk != "" && Veterancy != WeaponInfoList[i].Perk)
                || cLevel < WeaponInfoList[i].Level)
            {
                ReturnTrue++;
            }
        }
    }
    if (InList > 0 && ReturnTrue == InList)
        return true;
    return false;
}

function DropOrDestroy(Inventory Inv, Pawn Other)
{
    if (KFWeapon(Inv) == None)
        return;
    if (!KFWeapon(Inv).bKFNeverThrow)
    {
        if (PlayerController(Other.Controller) != None && bSendInfoMessage)
            PlayerController(Other.Controller).ClientMessage(MSG_Drop @ Inv.ItemName);
        Inv.DropFrom(Other.Location + vector(Other.Rotation) * ThrowDistance);
    }
    else if (bDestroy)
    {
        if (PlayerController(Other.Controller) != None && bSendInfoMessage)
            PlayerController(Other.Controller).ClientMessage(MSG_Drop @ Inv.ItemName);
        Inv.Destroy();
    }
}

function bool InExceptionList(Controller C)
{
    local PlayerController PC;
    local int i;
    local string Hash;

    PC = PlayerController(C);
    if (PC == None)
        return true;
    if (bAdminInExceptionList && C.PlayerReplicationInfo.bAdmin)
        return true;
    Hash = PC.GetPlayerIDHash();
    for (i = 0; i < ExceptionList.Length; i++)
    {
        if (ExceptionList[i] ~= Hash)
            return true;
    }
    return false;
}

defaultproperties
{
    ExceptionList(0)="76561198044444444"
    WeaponInfoList(0)=(Weapon="KFMod.Katana",Perk="SRVetBerserker",Level=4)
    WeaponInfoList(1)=(Weapon="KFMod.Deagle",Perk="SRVetSharpshooter",Level=4)
    WeaponInfoList(2)=(Weapon="KFMod.Katana",Perk="SRVetFieldMedic",Level=8)
    bSendInfoMessage=true
    MSG_Drop="Your perk and/or level is not good enough to possess"
    bDestroy=true
    bAdminInExceptionList=false
    TimerPeriod=2.0
    ThrowDistance=100
    bAddToServerPackages=True
    GroupName="KF-DropWeapons"
    FriendlyName="DropWeapons"
    Description="DropWeapons"
    bAlwaysRelevant=True
    RemoteRole=ROLE_SimulatedProxy
}
DropWeaponsMut.DropWeaponsMut

Скомпилированная версия: https://yadi.sk/d/PdqXk-b_dpfCo

Написал я этот мутатор и подумал
А ведь тому, кто меня просил небось просто нужен был мутатор, который выкидывает пушки чужого перка
Он же задерётся вбивать все пушки в инишник)
И сделал урезанную версию того же самого мутатора без всяких списков. Тупо проверяющую индекс перка и индекс пушки

Итак, мутатор выкидывает пушки принадлежащие чужому перку

ExceptionList=76561198044444444  - массив игроков на которых мутатор не действует
bAdminInExceptionList=false - принадлежат ли админы к исключениям? если true, то на всех кто сейчас находится под админкой мутатор не действует
TimerPeriod=1.000000 - период таймера в секундах, который осуществляет проверку легитимности)
bDestroy=True - некоторые пушки нельзя выкинуть, если значение этого параметра true - значит такие пушки просто будут уничтожаться
ThrowDistance=100 - расстояние на которое выбрасываются пушки впереди игрока
bSendInfoMessage=True - пишем ли мы сообщение игроку о выбрасывании пушки
MSG_Drop=You have wrong perk to possess - само сообщение. в конце данного сообщения автоматически добавляется название пушки (Weapon.ItemName)
class DropNonPerkWeaponsMut extends Mutator config(DropNonPerkWeaponsMut);

// Мутатор выкидывает оружие других перков (упрощённая схема по индексу перка).
var() globalconfig array<string> ExceptionList;
var() globalconfig bool bAdminInExceptionList;
var() globalconfig float TimerPeriod;
var() globalconfig bool bDestroy;
var() globalconfig int ThrowDistance;
var() globalconfig bool bSendInfoMessage;
var() globalconfig string MSG_Drop;

function PostBeginPlay()
{
    SaveConfig();
    SetTimer(TimerPeriod, true);
}

function Timer()
{
    local Controller C;

    for (C = Level.ControllerList; C != None; C = C.NextController)
    {
        if (C.IsA('PlayerController') && C.Pawn != None)
            ModifyPawn(C.Pawn);
    }
}

simulated function Tick(float Delta)
{
    local PlayerController PC;

    PC = Level.GetLocalPlayerController();
    if (PC != None && PC.Pawn != None && PC.Pawn.Weapon == None)
        PC.SwitchToBestWeapon();
}

function ModifyPawn(Pawn Other)
{
    local Inventory Inv;

    if (Other == None || Other.Inventory == None)
        return;
    for (Inv = Other.Inventory; Inv != None; Inv = Inv.Inventory)
    {
        if (InDropList(Inv, Other) && !InExceptionList(Other.Controller))
            DropOrDestroy(Inv, Other);
    }
}

function bool InDropList(Inventory Inv, Pawn Other)
{
    local int cLevel;
    local string Veterancy;
    local KFPlayerReplicationInfo KFPRI;
    local int PerkIndex;

    if (KFWeapon(Inv) == None)
        return false;
    KFPRI = KFPlayerReplicationInfo(Other.PlayerReplicationInfo);
    if (KFPRI != None)
    {
        cLevel = KFPRI.ClientVeteranSkillLevel;
        Veterancy = string(KFPRI.ClientVeteranSkill.Name);
        PerkIndex = KFPRI.ClientVeteranSkill.default.PerkIndex;
    }
    if (PerkIndex != class<KFWeaponPickup>(KFWeapon(Inv).PickupClass).default.CorrespondingPerkIndex)
        return true;
    return false;
}

function DropOrDestroy(Inventory Inv, Pawn Other)
{
    if (KFWeapon(Inv) == None)
        return;
    if (!KFWeapon(Inv).bKFNeverThrow)
    {
        if (PlayerController(Other.Controller) != None && bSendInfoMessage)
            PlayerController(Other.Controller).ClientMessage(MSG_Drop @ Inv.ItemName);
        Inv.DropFrom(Other.Location + vector(Other.Rotation) * ThrowDistance);
    }
    else if (bDestroy)
    {
        if (PlayerController(Other.Controller) != None && bSendInfoMessage)
            PlayerController(Other.Controller).ClientMessage(MSG_Drop @ Inv.ItemName);
        Inv.Destroy();
    }
}

function bool InExceptionList(Controller C)
{
    local PlayerController PC;
    local int i;
    local string Hash;

    PC = PlayerController(C);
    if (PC == None)
        return true;
    if (bAdminInExceptionList && C.PlayerReplicationInfo.bAdmin)
        return true;
    Hash = PC.GetPlayerIDHash();
    for (i = 0; i < ExceptionList.Length; i++)
    {
        if (ExceptionList[i] ~= Hash)
            return true;
    }
    return false;
}

defaultproperties
{
    ExceptionList(0)="76561198044444444"
    bSendInfoMessage=true
    MSG_Drop="You have wrong perk to possess"
    bDestroy=false
    bAdminInExceptionList=false
    TimerPeriod=1.0
    ThrowDistance=150
    bAddToServerPackages=True
    GroupName="KF-DropNonPerkWeapons"
    FriendlyName="DropNonPerkWeaponsMut"
    Description="DropNonPerkWeaponsMut"
    bAlwaysRelevant=True
    RemoteRole=ROLE_SimulatedProxy
}
DropNonPerkWeaponsMut.DropNonPerkWeaponsMut

Скомпилированная версия: https://yadi.sk/d/FzmWo6KNdpfUH

P.S.
Оба мутатора чуток спамят в лог при выкидывании пушек. Потом поправлю.

Warning: DropWeaponsMut KF-Meow-NewYearFix.DropWeaponsMut (Function DropWeaponsMut.DropWeaponsMut.ModifyPawn:008A) Accessed None 'Inv'

Автор: Flame