using ItemChanger; using ItemChanger.Placements; using ItemChanger.Tags; using System.Collections.Generic; using System.Linq; namespace Archipelago.HollowKnight.IC { internal class CostFactory { private Dictionary> locationCosts; /// /// Initializes a cost factory with costs provided from slot data /// /// A lookup from placement name -> cost type -> amount public CostFactory(Dictionary> locationCosts) { this.locationCosts = locationCosts; } public void ApplyCost(AbstractPlacement pmt, AbstractItem item, string serverLocationName) { if (locationCosts.TryGetValue(serverLocationName, out Dictionary costs)) { List icCosts = new(); foreach (KeyValuePair entry in costs) { Cost proposedCost = null; switch (entry.Key) { case "GEO": proposedCost = Cost.NewGeoCost(entry.Value); break; case "ESSENCE": proposedCost = Cost.NewEssenceCost(entry.Value); break; case "GRUBS": proposedCost = Cost.NewGrubCost(entry.Value); break; case "CHARMS": proposedCost = new PDIntCost( entry.Value, nameof(PlayerData.charmsOwned), $"Acquire {entry.Value} {((entry.Value == 1) ? "charm" : "charms")}" ); break; case "RANCIDEGGS": proposedCost = new ItemChanger.Modules.CumulativeRancidEggCost(entry.Value); break; default: ArchipelagoMod.Instance.LogWarn( $"Encountered UNKNOWN currency type {entry.Key} at location {serverLocationName}!"); break; } if (proposedCost != null) { // suppress inherent costs - if the server told us to pay X, but the implementation of // the location will force us to pay Y >= X, we skip adding the cost to prevent doubling up. IEnumerable inherentCosts = pmt.GetPlacementAndLocationTags() .OfType() .Where(t => t.Inherent) .Select(t => t.Cost); if (inherentCosts.Any(c => c.Includes(proposedCost))) { ArchipelagoMod.Instance.LogDebug($"Supressing cost {entry.Value} {entry.Key} for location {serverLocationName}"); continue; } else { icCosts.Add(proposedCost); } } } if (icCosts.Count == 0) { ArchipelagoMod.Instance.LogWarn( $"Found zero cost types when handling placement at location {serverLocationName}!"); return; } Cost finalCosts; if (icCosts.Count == 1) { finalCosts = icCosts[0]; } else { finalCosts = new MultiCost(icCosts); } if (pmt is ISingleCostPlacement scp) { if (scp.Cost == null) { scp.Cost = finalCosts; } else { scp.Cost = new MultiCost(scp.Cost, finalCosts); } } else { CostTag costTag = item.AddTag(); costTag.Cost = finalCosts; } } } } }