fix: Add CalamDropHelper Utilities to replace strong reference to CalamityMod
This commit is contained in:
parent
1a77650e1a
commit
c9b5ec17e6
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
# Auto-generated directories
|
||||
bin/
|
||||
obj/
|
||||
.vs/
|
|
@ -5,6 +5,7 @@ using Terraria.ID;
|
|||
using Terraria.ModLoader;
|
||||
using Terraria.GameContent.ItemDropRules;
|
||||
using Continuity.Content.Items;
|
||||
using continuity.Utilities;
|
||||
|
||||
namespace Continuity.Content
|
||||
{
|
||||
|
@ -47,7 +48,10 @@ namespace Continuity.Content
|
|||
itemLoot.RemoveWhere(rule => rule is OneFromRulesRule);
|
||||
if (ModLoader.HasMod("CalamityMod"))
|
||||
{
|
||||
itemLoot.RemoveWhere(rule => rule is CalamityMod.DropHelper.AllOptionsAtOnceWithPityDropRule);
|
||||
// NOTE(midnadimple): This line causes build issue in tModloader v2024.9.3.0, i dont think
|
||||
// this is how you're meant to access other mods' drop rules.
|
||||
itemLoot.RemoveWhere(rule => rule is CalamDropHelper.AllOptionsAtOnceWithPityDropRule);
|
||||
|
||||
if (ModLoader.TryGetMod("CalamityMod", out Mod calamityMod) && calamityMod.TryFind<ModItem>("BlossomFlux", out ModItem BlossomFlux)) {
|
||||
itemLoot.RemoveWhere(rule => rule is CommonDrop drop
|
||||
&& drop.itemId == BlossomFlux.Type);
|
||||
|
|
147
Utilities/CalamDropHelper.cs
Normal file
147
Utilities/CalamDropHelper.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using Terraria.GameContent.ItemDropRules;
|
||||
using Terraria.Utilities;
|
||||
using Terraria;
|
||||
|
||||
// Repurposed from https://github.com/CalamityTeam/CalamityModPublic/blob/1.4.4/Utilities/DropHelper.cs
|
||||
namespace continuity.Utilities
|
||||
{
|
||||
internal class CalamDropHelper
|
||||
{
|
||||
public struct Fraction
|
||||
{
|
||||
internal readonly int numerator;
|
||||
internal readonly int denominator;
|
||||
|
||||
public Fraction(int n, int d)
|
||||
{
|
||||
numerator = n < 0 ? 0 : n;
|
||||
denominator = d <= 0 ? 1 : d;
|
||||
}
|
||||
|
||||
public static implicit operator float(Fraction f) => f.numerator / (float)f.denominator;
|
||||
}
|
||||
|
||||
|
||||
public struct WeightedItemStack
|
||||
{
|
||||
public const float DefaultWeight = 1f;
|
||||
public const float MinisiculeWeight = 1E-6f;
|
||||
|
||||
internal int itemID;
|
||||
internal float weight;
|
||||
internal int minQuantity;
|
||||
internal int maxQuantity;
|
||||
|
||||
internal WeightedItemStack(int id, float w)
|
||||
{
|
||||
itemID = id;
|
||||
weight = w;
|
||||
minQuantity = 1;
|
||||
maxQuantity = 1;
|
||||
}
|
||||
|
||||
internal WeightedItemStack(int id, float w, int quantity)
|
||||
{
|
||||
itemID = id;
|
||||
weight = w;
|
||||
minQuantity = quantity;
|
||||
maxQuantity = quantity;
|
||||
}
|
||||
|
||||
internal WeightedItemStack(int id, float w, int min, int max)
|
||||
{
|
||||
itemID = id;
|
||||
weight = w;
|
||||
minQuantity = min;
|
||||
maxQuantity = max;
|
||||
}
|
||||
|
||||
internal int ChooseQuantity(UnifiedRandom rng) => rng.Next(minQuantity, maxQuantity + 1);
|
||||
|
||||
// Allow for implicitly casting integer item IDs into weighted item stacks.
|
||||
// Stack size is assumed to be 1. Weight is assumed to be default.
|
||||
public static implicit operator WeightedItemStack(int id)
|
||||
{
|
||||
return new WeightedItemStack(id, DefaultWeight, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public class AllOptionsAtOnceWithPityDropRule : IItemDropRule
|
||||
{
|
||||
public WeightedItemStack[] stacks;
|
||||
public Fraction dropRate;
|
||||
public bool usesLuck;
|
||||
public List<IItemDropRuleChainAttempt> ChainedRules { get; set; }
|
||||
|
||||
public AllOptionsAtOnceWithPityDropRule(Fraction dropRate, bool luck, params WeightedItemStack[] stacks)
|
||||
{
|
||||
this.dropRate = dropRate;
|
||||
this.stacks = stacks;
|
||||
usesLuck = luck;
|
||||
ChainedRules = new List<IItemDropRuleChainAttempt>();
|
||||
}
|
||||
|
||||
public AllOptionsAtOnceWithPityDropRule(Fraction dropRate, bool luck, params int[] itemIDs)
|
||||
{
|
||||
this.dropRate = dropRate;
|
||||
stacks = new WeightedItemStack[itemIDs.Length];
|
||||
for (int i = 0; i < stacks.Length; ++i)
|
||||
stacks[i] = itemIDs[i]; // implicit conversion operator
|
||||
usesLuck = luck;
|
||||
ChainedRules = new List<IItemDropRuleChainAttempt>();
|
||||
}
|
||||
|
||||
public bool CanDrop(DropAttemptInfo info) => true;
|
||||
|
||||
public ItemDropAttemptResult TryDroppingItem(DropAttemptInfo info)
|
||||
{
|
||||
bool droppedAnything = false;
|
||||
|
||||
// Roll for each drop individually.
|
||||
foreach (WeightedItemStack stack in stacks)
|
||||
{
|
||||
bool rngRoll = usesLuck ? info.player.RollLuck(dropRate.denominator) < dropRate.numerator : info.rng.NextFloat() < dropRate;
|
||||
droppedAnything |= rngRoll;
|
||||
if (rngRoll)
|
||||
CommonCode.DropItem(info, stack.itemID, stack.ChooseQuantity(info.rng));
|
||||
}
|
||||
|
||||
// If everything fails to drop, force drop one item from the set.
|
||||
if (!droppedAnything)
|
||||
{
|
||||
WeightedItemStack stack = info.rng.NextFromList(stacks);
|
||||
CommonCode.DropItem(info, stack.itemID, stack.ChooseQuantity(info.rng));
|
||||
}
|
||||
|
||||
// Calamity style drops cannot fail. You will always get at least one item.
|
||||
ItemDropAttemptResult result = default;
|
||||
result.State = ItemDropAttemptResultState.Success;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void ReportDroprates(List<DropRateInfo> drops, DropRateInfoChainFeed ratesInfo)
|
||||
{
|
||||
int numDrops = stacks.Length;
|
||||
float rawDropRate = dropRate;
|
||||
// Combinatorics:
|
||||
// OPTION 1: [The item drops = Raw Drop Rate]
|
||||
// +
|
||||
// OPTION 2: [ALL items fail to drop = (1-x)^n] * [This item is chosen as pity = 1/n]
|
||||
float dropRateWithPityRoll = rawDropRate + (float)(Math.Pow(1f - rawDropRate, numDrops) * (1f / numDrops));
|
||||
float dropRateAdjustedForParent = dropRateWithPityRoll * ratesInfo.parentDroprateChance;
|
||||
|
||||
// Report the drop rate of each individual item. This calculation includes the fact that each individual item can be guaranteed as pity.
|
||||
foreach (WeightedItemStack stack in stacks)
|
||||
drops.Add(new DropRateInfo(stack.itemID, stack.minQuantity, stack.maxQuantity, dropRateAdjustedForParent, ratesInfo.conditions));
|
||||
|
||||
Chains.ReportDroprates(ChainedRules, rawDropRate, drops, ratesInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in a new issue