Upload from upload_mods.ps1
This commit is contained in:
52
Scripts/Requirements/ActionHasTags.cs
Normal file
52
Scripts/Requirements/ActionHasTags.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using KFCommonUtilityLib;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class ActionHasTags : TargetedCompareRequirementBase
|
||||
{
|
||||
private FastTags<TagGroup.Global> actionTags;
|
||||
|
||||
private bool hasAllTags;
|
||||
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (!base.IsValid(_params))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool flag = false;
|
||||
if (_params.ItemActionData is IModuleContainerFor<ActionModuleTagged.TaggedData> tagged)
|
||||
{
|
||||
flag = (hasAllTags ? tagged.Instance.tags.Test_AllSet(actionTags) : tagged.Instance.tags.Test_AnySet(actionTags));
|
||||
}
|
||||
|
||||
if (!invert)
|
||||
{
|
||||
return flag;
|
||||
}
|
||||
|
||||
return !flag;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
bool flag = base.ParseXAttribute(_attribute);
|
||||
if (!flag)
|
||||
{
|
||||
string localName = _attribute.Name.LocalName;
|
||||
if (localName == "tags")
|
||||
{
|
||||
actionTags = FastTags<TagGroup.Global>.Parse(_attribute.Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (localName == "has_all_tags")
|
||||
{
|
||||
hasAllTags = StringParsers.ParseBool(_attribute.Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
31
Scripts/Requirements/ActionIndexIs.cs
Normal file
31
Scripts/Requirements/ActionIndexIs.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class ActionIndexIs : RequirementBase
|
||||
{
|
||||
protected int index;
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
//if (!res)
|
||||
//{
|
||||
// Log.Out($"Action index is not {index} : {(_params.ItemActionData == null ? "null" : _params.ItemActionData.indexInEntityOfAction.ToString())}\n{StackTraceUtility.ExtractStackTrace()}");
|
||||
//}
|
||||
var res = (_params.ItemActionData == null && index == 0) || _params.ItemActionData?.indexInEntityOfAction == index;
|
||||
return invert ? !res : res;
|
||||
}
|
||||
|
||||
public override bool ParamsValid(MinEventParams _params)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (_attribute.Name == "index")
|
||||
{
|
||||
index = Math.Max(int.Parse(_attribute.Value), 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
44
Scripts/Requirements/AmmoIndexIs.cs
Normal file
44
Scripts/Requirements/AmmoIndexIs.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using KFCommonUtilityLib.Scripts.Utilities;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class AmmoIndexIs : RequirementBase
|
||||
{
|
||||
protected int ammoIndex;
|
||||
protected int actionIndex;
|
||||
protected ItemValue itemValueCache;
|
||||
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
bool res = false;
|
||||
int parAmmoIndex = itemValueCache.GetSelectedAmmoIndexByActionIndex(actionIndex);
|
||||
res = parAmmoIndex == ammoIndex;
|
||||
itemValueCache = null;
|
||||
if (invert)
|
||||
{
|
||||
return !res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public override bool ParamsValid(MinEventParams _params)
|
||||
{
|
||||
itemValueCache = _params.ItemValue;
|
||||
return itemValueCache != null;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
switch(_attribute.Name.LocalName)
|
||||
{
|
||||
case "ammoIndex":
|
||||
ammoIndex = int.Parse(_attribute.Value);
|
||||
break;
|
||||
case "actionIndex":
|
||||
actionIndex = int.Parse(_attribute.Value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
32
Scripts/Requirements/FireModeIs.cs
Normal file
32
Scripts/Requirements/FireModeIs.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using KFCommonUtilityLib;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class FireModeIs : RequirementBase
|
||||
{
|
||||
protected int index;
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
bool res = false;
|
||||
if (_params.ItemActionData is IModuleContainerFor<ActionModuleFireModeSelector.FireModeData> dataModule)
|
||||
{
|
||||
res = dataModule.Instance.currentFireMode == index;
|
||||
}
|
||||
return invert ? !res : res;
|
||||
}
|
||||
|
||||
public override bool ParamsValid(MinEventParams _params)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (_attribute.Name == "index")
|
||||
{
|
||||
index = Math.Max(int.Parse(_attribute.Value), 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
9
Scripts/Requirements/HoldingActionIndexIs.cs
Normal file
9
Scripts/Requirements/HoldingActionIndexIs.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using KFCommonUtilityLib.Scripts.StaticManagers;
|
||||
|
||||
public class HoldingActionIndexIs : ActionIndexIs
|
||||
{
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
return (MultiActionManager.GetActionIndexForEntity(_params.Self) == index) ^ invert;
|
||||
}
|
||||
}
|
||||
8
Scripts/Requirements/HoldingAmmoIndexIs.cs
Normal file
8
Scripts/Requirements/HoldingAmmoIndexIs.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
public class HoldingAmmoIndexIs : AmmoIndexIs
|
||||
{
|
||||
public override bool ParamsValid(MinEventParams _params)
|
||||
{
|
||||
itemValueCache = _params.Self?.inventory?.holdingItemItemValue;
|
||||
return itemValueCache != null;
|
||||
}
|
||||
}
|
||||
33
Scripts/Requirements/HoldingFireModeIs.cs
Normal file
33
Scripts/Requirements/HoldingFireModeIs.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using KFCommonUtilityLib;
|
||||
using KFCommonUtilityLib.Scripts.StaticManagers;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class HoldingFireModeIs : RequirementBase
|
||||
{
|
||||
protected int index;
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
bool res = false;
|
||||
if (_params.Self && _params.Self?.inventory?.holdingItemData?.actionData[MultiActionManager.GetActionIndexForEntity(_params.Self)] is IModuleContainerFor<ActionModuleFireModeSelector.FireModeData> dataModule)
|
||||
{
|
||||
res = dataModule.Instance.currentFireMode == index;
|
||||
}
|
||||
return invert ? !res : res;
|
||||
}
|
||||
|
||||
public override bool ParamsValid(MinEventParams _params)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (_attribute.Name == "index")
|
||||
{
|
||||
index = Math.Max(int.Parse(_attribute.Value), 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
28
Scripts/Requirements/IsActionUnlocked.cs
Normal file
28
Scripts/Requirements/IsActionUnlocked.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using KFCommonUtilityLib;
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class IsActionUnlocked : TargetedCompareRequirementBase
|
||||
{
|
||||
protected int actionIndex;
|
||||
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
return base.IsValid(_params) &&
|
||||
((actionIndex == 0 ||
|
||||
(_params.ItemActionData?.invData?.actionData?[0] is IModuleContainerFor<ActionModuleAlternative.AlternativeData> alt
|
||||
&& alt.Instance.IsActionUnlocked(actionIndex))) ^ invert);
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (base.ParseXAttribute(_attribute))
|
||||
return true;
|
||||
|
||||
if (_attribute.Name == "index")
|
||||
{
|
||||
actionIndex = int.Parse(_attribute.Value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
64
Scripts/Requirements/IsHoldingItemModificationActivated.cs
Normal file
64
Scripts/Requirements/IsHoldingItemModificationActivated.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using UniLinq;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class IsHoldingItemModificationActivated : RequirementBase
|
||||
{
|
||||
private string modName;
|
||||
private int modId = -1;
|
||||
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (modId < 0)
|
||||
{
|
||||
modId = ItemClass.GetItemClass(modName)?.Id ?? -1;
|
||||
//Log.Out($"modId {modId}");
|
||||
if (modId < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemValue itemValue = _params.Self?.inventory?.holdingItemItemValue;
|
||||
//Log.Out($"modName {modName} modId {modId} item {_params?.ItemValue?.ItemClass?.Name ?? "null"} mods{(_params?.ItemValue?.Modifications == null ? ": null" : itemValue.Modifications.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \ncos{(_params?.ItemValue?.CosmeticMods == null ? ": null" : itemValue.CosmeticMods.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \n{StackTraceUtility.ExtractStackTrace()}");
|
||||
if (itemValue != null)
|
||||
{
|
||||
if (itemValue.Modifications != null)
|
||||
{
|
||||
foreach (var mod in itemValue.Modifications)
|
||||
{
|
||||
if (mod != null && mod.type == modId && mod.Activated > 0)
|
||||
{
|
||||
return !invert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemValue.CosmeticMods != null)
|
||||
{
|
||||
foreach (var cos in itemValue.CosmeticMods)
|
||||
{
|
||||
if (cos != null && cos.type == modId && cos.Activated > 0)
|
||||
{
|
||||
return !invert;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return invert;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (base.ParseXAttribute(_attribute))
|
||||
return true;
|
||||
|
||||
switch (_attribute.Name.LocalName)
|
||||
{
|
||||
case "mod":
|
||||
modName = _attribute.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
15
Scripts/Requirements/IsInJeep.cs
Normal file
15
Scripts/Requirements/IsInJeep.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
public class IsInJeep : IsAttachedToEntity
|
||||
{
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (!base.IsValid(_params))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (invert)
|
||||
{
|
||||
return !(target.AttachedToEntity is EntityVJeep);
|
||||
}
|
||||
return target.AttachedToEntity is EntityVJeep;
|
||||
}
|
||||
}
|
||||
7
Scripts/Requirements/IsLocal.cs
Normal file
7
Scripts/Requirements/IsLocal.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
public class IsLocal : RequirementBase
|
||||
{
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
return base.IsValid(_params) && ((_params.IsLocal || (_params.Self && !_params.Self.isEntityRemote)) ^ invert);
|
||||
}
|
||||
}
|
||||
63
Scripts/Requirements/IsModificationActivated.cs
Normal file
63
Scripts/Requirements/IsModificationActivated.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using UniLinq;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class IsModificationActivated : RequirementBase
|
||||
{
|
||||
private string modName;
|
||||
private int modId = -1;
|
||||
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (modId < 0)
|
||||
{
|
||||
modId = ItemClass.GetItemClass(modName)?.Id ?? -1;
|
||||
//Log.Out($"modId {modId}");
|
||||
if (modId < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
//Log.Out($"modName {modName} modId {modId} item {_params?.ItemValue?.ItemClass?.Name ?? "null"} mods{(_params?.ItemValue?.Modifications == null ? ": null" : _params.ItemValue.Modifications.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \ncos{(_params?.ItemValue?.CosmeticMods == null ? ": null" : _params.ItemValue.CosmeticMods.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \n{StackTraceUtility.ExtractStackTrace()}");
|
||||
if (_params.ItemValue != null)
|
||||
{
|
||||
if (_params.ItemValue.Modifications != null)
|
||||
{
|
||||
foreach (var mod in _params.ItemValue.Modifications)
|
||||
{
|
||||
if (mod != null && mod.type == modId && mod.Activated > 0)
|
||||
{
|
||||
return !invert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_params.ItemValue.CosmeticMods != null)
|
||||
{
|
||||
foreach (var cos in _params.ItemValue.CosmeticMods)
|
||||
{
|
||||
if (cos != null && cos.type == modId && cos.Activated > 0)
|
||||
{
|
||||
return !invert;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return invert;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (base.ParseXAttribute(_attribute))
|
||||
return true;
|
||||
|
||||
switch (_attribute.Name.LocalName)
|
||||
{
|
||||
case "mod":
|
||||
modName = _attribute.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
7
Scripts/Requirements/ItemActionIndexIs.cs
Normal file
7
Scripts/Requirements/ItemActionIndexIs.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
//public class ItemActionIndexIs : ActionIndexIs
|
||||
//{
|
||||
// public override bool IsValid(MinEventParams _params)
|
||||
// {
|
||||
// return (_params.ItemValue == null && index == 0) || _params.ItemValue?.GetActionIndexForItemValue() == index;
|
||||
// }
|
||||
//}
|
||||
33
Scripts/Requirements/ItemInInventory.cs
Normal file
33
Scripts/Requirements/ItemInInventory.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class ItemInInventory : RequirementBase
|
||||
{
|
||||
private string itemName;
|
||||
private ItemValue itemValueCache = null;
|
||||
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
return base.IsValid(_params) && compareValues(_params.Self.GetItemCount(itemValueCache), operation, value) ^ invert;
|
||||
}
|
||||
|
||||
public override bool ParamsValid(MinEventParams _params)
|
||||
{
|
||||
if (itemValueCache == null)
|
||||
itemValueCache = ItemClass.GetItem(itemName);
|
||||
return base.ParamsValid(_params) && itemValueCache != null;
|
||||
}
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (base.ParseXAttribute(_attribute))
|
||||
return true;
|
||||
|
||||
string name = _attribute.Name.LocalName;
|
||||
if (name == "item")
|
||||
{
|
||||
itemName = _attribute.Value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
17
Scripts/Requirements/PercentInHoldingItem.cs
Normal file
17
Scripts/Requirements/PercentInHoldingItem.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using KFCommonUtilityLib.Scripts.StaticManagers;
|
||||
|
||||
public class PercentInHoldingItem : RoundsInHoldingItem
|
||||
{
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (!ParamsValid(_params))
|
||||
return false;
|
||||
|
||||
ItemValue holdingItemValue = _params.Self.inventory.holdingItemItemValue;
|
||||
int actionIndex = MultiActionManager.GetActionIndexForEntity(_params.Self);
|
||||
if (holdingItemValue.IsEmpty() || !(holdingItemValue.ItemClass.Actions[actionIndex] is ItemActionRanged _ranged))
|
||||
return false;
|
||||
return RequirementBase.compareValues((float)(roundsBeforeShot ? holdingItemValue.Meta + 1 : holdingItemValue.Meta) / _ranged.GetMaxAmmoCount(_params.Self.inventory.holdingItemData.actionData[actionIndex]), operation, value) ^ invert;
|
||||
}
|
||||
}
|
||||
|
||||
14
Scripts/Requirements/PercentInMagazine.cs
Normal file
14
Scripts/Requirements/PercentInMagazine.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
public class PercentInMagazine : RoundsInMagazineBase
|
||||
{
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (!ParamsValid(_params))
|
||||
return false;
|
||||
|
||||
if (_params.ItemValue.IsEmpty() || !(_params.ItemActionData is ItemActionRanged.ItemActionDataRanged _rangedData) || _params.ItemActionData.invData == null)
|
||||
return false;
|
||||
|
||||
return RequirementBase.compareValues((float)(roundsBeforeShot ? _params.ItemValue.Meta + 1 : _params.ItemValue.Meta) / ((ItemActionRanged)_params.ItemValue.ItemClass.Actions[_rangedData.indexInEntityOfAction]).GetMaxAmmoCount(_params.ItemActionData), operation, value) ^ invert;
|
||||
}
|
||||
}
|
||||
|
||||
17
Scripts/Requirements/RoundsInHoldingItem.cs
Normal file
17
Scripts/Requirements/RoundsInHoldingItem.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using KFCommonUtilityLib.Scripts.StaticManagers;
|
||||
|
||||
public class RoundsInHoldingItem : RoundsInMagazineBase
|
||||
{
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (!ParamsValid(_params))
|
||||
return false;
|
||||
|
||||
ItemValue holdingItemValue = _params.Self.inventory.holdingItemItemValue;
|
||||
if (holdingItemValue.IsEmpty() || !(holdingItemValue.ItemClass.Actions[MultiActionManager.GetActionIndexForEntity(_params.Self)] is ItemActionRanged))
|
||||
return false;
|
||||
|
||||
return RequirementBase.compareValues((float)(roundsBeforeShot ? holdingItemValue.Meta + 1 : holdingItemValue.Meta), operation, value) ^ invert;
|
||||
}
|
||||
}
|
||||
|
||||
32
Scripts/Requirements/RoundsInInventory.cs
Normal file
32
Scripts/Requirements/RoundsInInventory.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class RoundsInInventory : RequirementBase
|
||||
{
|
||||
private static Dictionary<string, ItemValue> cached = new Dictionary<string, ItemValue>();
|
||||
|
||||
public static bool TryGetValue(string ammoName, out ItemValue ammoValue)
|
||||
{
|
||||
if (!cached.TryGetValue(ammoName, out ammoValue))
|
||||
{
|
||||
ammoValue = ItemClass.GetItem(ammoName, false);
|
||||
if (ammoValue == null)
|
||||
return false;
|
||||
cached.Add(ammoName, ammoValue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public override bool IsValid(MinEventParams _params)
|
||||
{
|
||||
if (!this.ParamsValid(_params))
|
||||
return invert;
|
||||
|
||||
ItemValue itemValue = _params.ItemValue;
|
||||
if (itemValue.IsEmpty() || !(_params.ItemActionData is ItemActionRanged.ItemActionDataRanged _rangedData))
|
||||
return invert;
|
||||
|
||||
string ammoName = ((ItemActionRanged)itemValue.ItemClass.Actions[_rangedData.indexInEntityOfAction]).MagazineItemNames[itemValue.SelectedAmmoTypeIndex];
|
||||
if (TryGetValue(ammoName, out var ammoValue))
|
||||
return compareValues(_params.Self.GetItemCount(ammoValue), this.operation, this.value) ^ invert;
|
||||
return invert;
|
||||
}
|
||||
}
|
||||
21
Scripts/Requirements/RoundsInMagazineBase.cs
Normal file
21
Scripts/Requirements/RoundsInMagazineBase.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
public class RoundsInMagazineBase : RoundsInMagazine
|
||||
{
|
||||
protected bool roundsBeforeShot = false;
|
||||
|
||||
public override bool ParseXAttribute(XAttribute _attribute)
|
||||
{
|
||||
if (base.ParseXAttribute(_attribute))
|
||||
return true;
|
||||
|
||||
if (_attribute.Name.LocalName == "rounds_before_shot")
|
||||
{
|
||||
roundsBeforeShot = bool.Parse(_attribute.Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user