forked from aly/qstbak
muffin v7.5.6
This commit is contained in:
parent
6266f9e6b7
commit
addf2d530f
619 changed files with 264792 additions and 446022 deletions
|
|
@ -0,0 +1,411 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Dalamud.Plugin.Services;
|
||||
using LLib.Inventory;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace Questionable.Controller.CustomDelivery;
|
||||
|
||||
internal sealed class DeliveryRewardCalculator(IDataManager dataManager)
|
||||
{
|
||||
internal record struct CurrencyReward(uint CurrencyItemId, string CurrencyName, int AmountPerDelivery)
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[CompilerGenerated]
|
||||
public override readonly string ToString()
|
||||
{
|
||||
StringBuilder stringBuilder = _206A_200C_202B_206F_202E_202C_202C_200D_200D_206E_200C_206C_202C_200F_206F_206E_202C_200D_200C_202E_206A_206A_206C_202A_206C_206A_200E_200D_202E_200B_206A_202D_202A_206A_206B_206F_206C_200B_206B_202B_202E();
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(stringBuilder, global::_003CModule_003E._200B_206B_206B_200E_200B_206A_206D_206B_206E_200F_206A_206F_206E_202B_200F_206C_202B_206D_206E_200F_200C_200E_206F_200D_200F_200B_202B_202B_202B_202B_206D_202C_206A_206D_200B_206E_200D_206A_206F_200F_202E<string>(175214569));
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(stringBuilder, global::_003CModule_003E._202A_206B_206D_200C_206B_200E_200E_202A_200B_202E_206A_206F_206A_206B_200E_200D_200F_206D_206E_206A_206F_200C_206C_202C_202A_206E_202C_200B_206E_202A_206E_202B_206B_202E_202E_206A_206D_206D_202C_200F_202E<string>(1664411125));
|
||||
int num = ((!PrintMembers(stringBuilder)) ? 851670769 : 851670770);
|
||||
while (true)
|
||||
{
|
||||
int num2 = num;
|
||||
int num3 = 851670771;
|
||||
int num4 = num2;
|
||||
int num5 = num4 + num3;
|
||||
int num6 = num4 & num3;
|
||||
switch (num5 - (num6 + num6))
|
||||
{
|
||||
case 0:
|
||||
num = 851670770;
|
||||
break;
|
||||
case 2:
|
||||
_206E_200E_200B_200B_200F_206E_202C_206A_200B_200B_206C_206C_202C_200E_206A_202A_206D_202E_202C_206C_200F_206B_202C_206A_206C_202B_200B_200E_202B_200B_200E_202C_202B_206F_202E_200D_202D_202C_206B_206D_202E(stringBuilder, '}');
|
||||
return _200C_200D_200C_200E_206A_202A_206A_202A_202B_200B_200D_200E_200C_200F_200B_200D_206B_206D_200F_200D_206B_206B_206C_202E_206F_202E_200E_200C_200E_206F_200B_206B_202A_206A_206D_206C_200C_206C_206A_206E_202E((object)stringBuilder);
|
||||
case 1:
|
||||
_206E_200E_200B_200B_200F_206E_202C_206A_200B_200B_206C_206C_202C_200E_206A_202A_206D_202E_202C_206C_200F_206B_202C_206A_206C_202B_200B_200E_202B_200B_200E_202C_202B_206F_202E_200D_202D_202C_206B_206D_202E(stringBuilder, ' ');
|
||||
num = 851670769;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[CompilerGenerated]
|
||||
private readonly bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(builder, global::_003CModule_003E._202D_206D_206A_206E_202C_202B_200C_206C_200E_206A_206D_200E_206A_202A_200C_202E_206E_202C_206F_200B_206D_206F_200C_202C_200B_202B_200F_200B_206A_206F_200F_202E_206B_200E_202B_202A_200F_200B_202A_200E_202E<string>(557355409));
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(builder, CurrencyItemId.ToString());
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(builder, global::_003CModule_003E._206C_202A_206D_206A_206E_202A_202B_206F_206D_200F_202D_200F_202D_206A_202C_202B_206D_206A_200E_200E_202D_202D_200D_200C_200D_200D_206D_206E_202A_200F_206E_206C_206D_206A_206D_202B_200F_200D_206E_200C_202E<string>(-1370044589));
|
||||
_200B_206F_200D_202B_202B_200C_206C_206F_202B_202C_206D_200F_206F_200D_206D_206C_200F_206B_206A_206A_200F_202E_206B_202B_206B_200D_206E_202B_206A_200E_206F_202E_206B_206C_202B_200F_200F_202D_200E_206C_202E(builder, (object)CurrencyName);
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(builder, global::_003CModule_003E._200B_206B_206B_200E_200B_206A_206D_206B_206E_200F_206A_206F_206E_202B_200F_206C_202B_206D_206E_200F_200C_200E_206F_200D_200F_200B_202B_202B_202B_202B_206D_202C_206A_206D_200B_206E_200D_206A_206F_200F_202E<string>(1289637212));
|
||||
_200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(builder, AmountPerDelivery.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
[CompilerGenerated]
|
||||
public readonly bool Equals(CurrencyReward other)
|
||||
{
|
||||
int num = ((!EqualityComparer<uint>.Default.Equals(CurrencyItemId, other.CurrencyItemId)) ? (-1286878871) : (-1286878870));
|
||||
while (true)
|
||||
{
|
||||
int num2 = num;
|
||||
int num3 = -1286878869;
|
||||
int num4 = num2;
|
||||
switch ((num4 | num3) - (num4 & num3))
|
||||
{
|
||||
case 2:
|
||||
return false;
|
||||
case 1:
|
||||
num = ((!EqualityComparer<string>.Default.Equals(CurrencyName, other.CurrencyName)) ? (-1286878871) : (-1286878869));
|
||||
break;
|
||||
case 0:
|
||||
return EqualityComparer<int>.Default.Equals(AmountPerDelivery, other.AmountPerDelivery);
|
||||
case 3:
|
||||
num = -1286878870;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IEquatable<CurrencyReward>.Equals(CurrencyReward other)
|
||||
{
|
||||
//ILSpy generated this explicit interface implementation from .override directive in Equals
|
||||
return this.Equals(other);
|
||||
}
|
||||
|
||||
static StringBuilder _206A_200C_202B_206F_202E_202C_202C_200D_200D_206E_200C_206C_202C_200F_206F_206E_202C_200D_200C_202E_206A_206A_206C_202A_206C_206A_200E_200D_202E_200B_206A_202D_202A_206A_206B_206F_206C_200B_206B_202B_202E()
|
||||
{
|
||||
return new StringBuilder();
|
||||
}
|
||||
|
||||
static StringBuilder _200C_200E_206E_206A_206D_202A_206B_202A_206A_202D_206F_200F_202E_200B_200B_206E_200F_202C_206E_206F_200D_200B_206E_202C_200B_202A_200B_200F_202A_200F_206E_200C_206B_200F_202A_200F_200E_206A_202C_202B_202E(StringBuilder P_0, string P_1)
|
||||
{
|
||||
return P_0.Append(P_1);
|
||||
}
|
||||
|
||||
static StringBuilder _206E_200E_200B_200B_200F_206E_202C_206A_200B_200B_206C_206C_202C_200E_206A_202A_206D_202E_202C_206C_200F_206B_202C_206A_206C_202B_200B_200E_202B_200B_200E_202C_202B_206F_202E_200D_202D_202C_206B_206D_202E(StringBuilder P_0, char P_1)
|
||||
{
|
||||
return P_0.Append(P_1);
|
||||
}
|
||||
|
||||
static string _200C_200D_200C_200E_206A_202A_206A_202A_202B_200B_200D_200E_200C_200F_200B_200D_206B_206D_200F_200D_206B_206B_206C_202E_206F_202E_200E_200C_200E_206F_200B_206B_202A_206A_206D_206C_200C_206C_206A_206E_202E(object P_0)
|
||||
{
|
||||
return P_0.ToString();
|
||||
}
|
||||
|
||||
static StringBuilder _200B_206F_200D_202B_202B_200C_206C_206F_202B_202C_206D_200F_206F_200D_206D_206C_200F_206B_206A_206A_200F_202E_206B_202B_206B_200D_206E_202B_206A_200E_206F_202E_206B_206C_202B_200F_200F_202D_200E_206C_202E(StringBuilder P_0, object P_1)
|
||||
{
|
||||
return P_0.Append(P_1);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<uint, int> ScripCaps = new Dictionary<uint, int>
|
||||
{
|
||||
[33913u] = 4000,
|
||||
[41784u] = 4000
|
||||
};
|
||||
|
||||
internal List<CurrencyReward> CalculateRewards(uint rewardRowId, bool hasBonus, Configuration.CustomDeliveryConfiguration.ECollectabilityTier tier = Configuration.CustomDeliveryConfiguration.ECollectabilityTier.High)
|
||||
{
|
||||
List<CurrencyReward> list = new List<CurrencyReward>();
|
||||
int num = (dataManager.GetExcelSheet<SatisfactionSupplyReward>().TryGetRow(rewardRowId, out var row) ? 1083172624 : 1083172627);
|
||||
uint rewardCurrency = default(uint);
|
||||
int num8 = default(int);
|
||||
ushort num9 = default(ushort);
|
||||
SatisfactionSupplyReward.SatisfactionSupplyRewardDataStruct current = default(SatisfactionSupplyReward.SatisfactionSupplyRewardDataStruct);
|
||||
while (true)
|
||||
{
|
||||
int num2 = num;
|
||||
int num3 = 1083172625;
|
||||
int num4 = num2;
|
||||
switch ((num4 | num3) - (num4 & num3))
|
||||
{
|
||||
case 0:
|
||||
goto IL_006c;
|
||||
case 2:
|
||||
return list;
|
||||
case 1:
|
||||
{
|
||||
using Collection<SatisfactionSupplyReward.SatisfactionSupplyRewardDataStruct>.Enumerator enumerator = row.SatisfactionSupplyRewardData.GetEnumerator();
|
||||
num = 328961127;
|
||||
while (true)
|
||||
{
|
||||
int num5 = num;
|
||||
num3 = 328961135;
|
||||
num4 = num5;
|
||||
int num6 = num4 + num3;
|
||||
int num7 = num4 & num3;
|
||||
switch (num6 - (num7 + num7))
|
||||
{
|
||||
case 6:
|
||||
{
|
||||
string currencyName = GetCurrencyName(rewardCurrency);
|
||||
list.Add(new CurrencyReward(rewardCurrency, currencyName, num8));
|
||||
num = 328961127;
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
num = ((tier != Configuration.CustomDeliveryConfiguration.ECollectabilityTier.Low) ? 328961125 : 328961132);
|
||||
break;
|
||||
case 4:
|
||||
num = ((tier == Configuration.CustomDeliveryConfiguration.ECollectabilityTier.Mid) ? 328961128 : 328961126);
|
||||
break;
|
||||
case 1:
|
||||
num8 = num9;
|
||||
num = ((!hasBonus) ? 328961129 : 328961135);
|
||||
break;
|
||||
case 11:
|
||||
num = 328961127;
|
||||
break;
|
||||
case 10:
|
||||
num9 = current.QuantityHigh;
|
||||
num = 328961134;
|
||||
break;
|
||||
case 3:
|
||||
num9 = current.QuantityLow;
|
||||
num = 328961134;
|
||||
break;
|
||||
case 8:
|
||||
num = (enumerator.MoveNext() ? 328961130 : 328961133);
|
||||
break;
|
||||
case 5:
|
||||
current = enumerator.Current;
|
||||
rewardCurrency = current.RewardCurrency;
|
||||
num = ((rewardCurrency == 0) ? 328961127 : 328961131);
|
||||
break;
|
||||
case 7:
|
||||
num9 = current.QuantityMid;
|
||||
num = 328961134;
|
||||
break;
|
||||
case 0:
|
||||
num8 = num8 * row.BonusMultiplier / 100;
|
||||
num = 328961129;
|
||||
break;
|
||||
case 2:
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
IL_006c:
|
||||
num = 1083172627;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool WouldOvercap(uint currencyItemId, int amountPerDelivery, int deliveryCount)
|
||||
{
|
||||
int value;
|
||||
int num = (ScripCaps.TryGetValue(currencyItemId, out value) ? (-1863089792) : (-1863089789));
|
||||
while (true)
|
||||
{
|
||||
int num2 = num;
|
||||
int num3 = -1863089790;
|
||||
int num4 = num2;
|
||||
switch ((num4 | num3) - (num4 & num3))
|
||||
{
|
||||
case 0:
|
||||
goto IL_004d;
|
||||
case 1:
|
||||
return false;
|
||||
case 2:
|
||||
return _202B_200E_206D_200C_206E_200D_202B_206E_206A_200C_200B_206E_202A_206F_202B_200F_206C_202C_200F_200C_202B_206A_202D_206D_202C_202E_206B_202D_206D_202A_206A_200B_206C_206F_206C_202B_200D_202E_206A_202A_202E(currencyItemId, false, false) + amountPerDelivery * deliveryCount > value;
|
||||
}
|
||||
continue;
|
||||
IL_004d:
|
||||
num = -1863089789;
|
||||
}
|
||||
}
|
||||
|
||||
internal int MaxDeliveriesBeforeOvercap(uint rewardRowId, bool hasBonus, Configuration.CustomDeliveryConfiguration.ECollectabilityTier tier = Configuration.CustomDeliveryConfiguration.ECollectabilityTier.High)
|
||||
{
|
||||
List<CurrencyReward> list = CalculateRewards(rewardRowId, hasBonus, tier);
|
||||
int num = int.MaxValue;
|
||||
int num2;
|
||||
using (List<CurrencyReward>.Enumerator enumerator = list.GetEnumerator())
|
||||
{
|
||||
num2 = -1256353988;
|
||||
int num10 = default(int);
|
||||
CurrencyReward current = default(CurrencyReward);
|
||||
int value = default(int);
|
||||
while (true)
|
||||
{
|
||||
int num3 = num2;
|
||||
int num4 = -1256353985;
|
||||
int num5 = num3;
|
||||
int num6 = num5 + num4;
|
||||
int num7 = num5 & num4;
|
||||
int num12;
|
||||
int num11;
|
||||
switch (num6 - (num7 + num7))
|
||||
{
|
||||
case 4:
|
||||
num12 = num10 / current.AmountPerDelivery;
|
||||
goto IL_006d;
|
||||
case 1:
|
||||
current = enumerator.Current;
|
||||
num2 = ((!ScripCaps.TryGetValue(current.CurrencyItemId, out value)) ? (-1256353988) : (-1256353985));
|
||||
break;
|
||||
case 2:
|
||||
num2 = -1256353988;
|
||||
break;
|
||||
case 5:
|
||||
num12 = 0;
|
||||
goto IL_006d;
|
||||
case 3:
|
||||
num2 = (enumerator.MoveNext() ? (-1256353986) : (-1256353992));
|
||||
break;
|
||||
case 0:
|
||||
num2 = ((current.AmountPerDelivery <= 0) ? (-1256353988) : (-1256353991));
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
int num8 = _202B_200E_206D_200C_206E_200D_202B_206E_206A_200C_200B_206E_202A_206F_202B_200F_206C_202C_200F_200C_202B_206A_202D_206D_202C_202E_206B_202D_206D_202A_206A_200B_206C_206F_206C_202B_200D_202E_206A_202A_202E(current.CurrencyItemId, false, false);
|
||||
int num9 = value;
|
||||
num4 = num8;
|
||||
num5 = num9;
|
||||
num10 = ~(~num5 + num4);
|
||||
num2 = ((num10 > 0) ? (-1256353989) : (-1256353990));
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
goto end_IL_0021;
|
||||
IL_006d:
|
||||
num11 = num12;
|
||||
num = _200E_202E_200C_200F_206B_206C_200E_200B_202A_206A_200D_200D_200D_202A_200D_200C_206B_202A_200B_206C_206C_202A_200E_200F_206E_206E_200D_206B_206B_206F_202E_206C_200B_202B_206B_206A_202B_200E_206A_200D_202E(num, num11);
|
||||
num2 = -1256353988;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
end_IL_0021:
|
||||
break;
|
||||
}
|
||||
}
|
||||
num2 = ((num == int.MaxValue) ? 1414795502 : 1414795503);
|
||||
while (true)
|
||||
{
|
||||
int num13 = num2;
|
||||
int num4 = 1414795502;
|
||||
int num5 = num13;
|
||||
switch ((num5 | num4) - (num5 & num4))
|
||||
{
|
||||
case 2:
|
||||
goto IL_01c5;
|
||||
case 1:
|
||||
return num;
|
||||
case 0:
|
||||
return int.MaxValue;
|
||||
}
|
||||
continue;
|
||||
IL_01c5:
|
||||
num2 = 1414795503;
|
||||
}
|
||||
}
|
||||
|
||||
internal int CalculateSatisfactionPerDelivery(uint rewardRowId, bool hasBonus, Configuration.CustomDeliveryConfiguration.ECollectabilityTier tier = Configuration.CustomDeliveryConfiguration.ECollectabilityTier.High)
|
||||
{
|
||||
SatisfactionSupplyReward row;
|
||||
int num = (dataManager.GetExcelSheet<SatisfactionSupplyReward>().TryGetRow(rewardRowId, out row) ? 284816978 : 284816979);
|
||||
ushort num8 = default(ushort);
|
||||
int num7 = default(int);
|
||||
while (true)
|
||||
{
|
||||
int num2 = num;
|
||||
int num3 = 284816978;
|
||||
int num4 = num2;
|
||||
int num5 = num4 + num3;
|
||||
int num6 = num4 & num3;
|
||||
switch (num5 - (num6 + num6))
|
||||
{
|
||||
case 5:
|
||||
num8 = row.SatisfactionHigh;
|
||||
num = 284816981;
|
||||
break;
|
||||
case 4:
|
||||
num = ((tier != Configuration.CustomDeliveryConfiguration.ECollectabilityTier.Low) ? 284816983 : 284816977);
|
||||
break;
|
||||
case 0:
|
||||
num = ((tier == Configuration.CustomDeliveryConfiguration.ECollectabilityTier.Mid) ? 284816980 : 284816982);
|
||||
break;
|
||||
case 6:
|
||||
num8 = row.SatisfactionMid;
|
||||
num = 284816981;
|
||||
break;
|
||||
case 9:
|
||||
return num7;
|
||||
case 7:
|
||||
num7 = num8;
|
||||
num = ((!hasBonus) ? 284816987 : 284816986);
|
||||
break;
|
||||
case 2:
|
||||
num = 284816979;
|
||||
break;
|
||||
case 3:
|
||||
num8 = row.SatisfactionLow;
|
||||
num = 284816981;
|
||||
break;
|
||||
case 8:
|
||||
num7 = num7 * row.BonusMultiplier / 100;
|
||||
num = 284816987;
|
||||
break;
|
||||
case 1:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private string GetCurrencyName(uint currencyItemId)
|
||||
{
|
||||
Item row;
|
||||
int num = ((!dataManager.GetExcelSheet<Item>().TryGetRow(currencyItemId, out row)) ? (-1217003400) : (-1217003397));
|
||||
while (true)
|
||||
{
|
||||
int num2 = num;
|
||||
int num3 = -1217003399;
|
||||
int num4 = num2;
|
||||
switch ((num4 | num3) - (num4 & num3))
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(9, 1);
|
||||
defaultInterpolatedStringHandler.AppendLiteral(global::_003CModule_003E._202A_206B_206D_200C_206B_200E_200E_202A_200B_202E_206A_206F_206A_206B_200E_200D_200F_206D_206E_206A_206F_200C_206C_202C_202A_206E_202C_200B_206E_202A_206E_202B_206B_202E_202E_206A_206D_206D_202C_200F_202E<string>(1297490435));
|
||||
defaultInterpolatedStringHandler.AppendFormatted(currencyItemId);
|
||||
return defaultInterpolatedStringHandler.ToStringAndClear();
|
||||
}
|
||||
case 2:
|
||||
return row.Name.ToString();
|
||||
case 0:
|
||||
goto IL_00a7;
|
||||
}
|
||||
continue;
|
||||
IL_00a7:
|
||||
num = -1217003397;
|
||||
}
|
||||
}
|
||||
|
||||
static int _202B_200E_206D_200C_206E_200D_202B_206E_206A_200C_200B_206E_202A_206F_202B_200F_206C_202C_200F_200C_202B_206A_202D_206D_202C_202E_206B_202D_206D_202A_206A_200B_206C_206F_206C_202B_200D_202E_206A_202A_202E(uint P_0, bool P_1, bool P_2)
|
||||
{
|
||||
return InventoryHelper.GetItemCount(P_0, P_1, P_2);
|
||||
}
|
||||
|
||||
static int _200E_202E_200C_200F_206B_206C_200E_200B_202A_206A_200D_200D_200D_202A_200D_200C_206B_202A_200B_206C_206C_202A_200E_200F_206E_206E_200D_206B_206B_206F_202E_206C_200B_202B_206B_206A_202B_200E_206A_200D_202E(int P_0, int P_1)
|
||||
{
|
||||
return Math.Min(P_0, P_1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue