private void CreateRelicModel(EquipSlot s, Equipment e) { var gv = gear[s, e]; RelicConfig config = null; SolverConfig.RelicConfigs.TryGetValue(e.ItemLevel.Key, out config); if (config == null || !config.Items.Contains(e.Key)) { return; } var isNonSurjective = config.ConversionFunction != null; var statCap = config.StatCapOverrides.ContainsKey(Job) && config.StatCapOverrides[Job].ContainsKey(s) ? config.StatCapOverrides[Job][s] : config.StatCap; Model.AddConstraint( Expression.Sum(RelevantStats.Select(bp => isNonSurjective ? relicBase[s, e, bp] : cap[s, e, bp])) <= statCap * gv, $"total relic cap for {e} in slot {s}"); foreach (var bp in RelevantStats) { var remCap = e.GetMateriaMeldCap(bp, true); if (remCap == 0) { continue; } var cv = cap[s, e, bp]; var func = config.ConversionFunction; if (config.ConversionOverride != null && config.ConversionOverride.ContainsKey(bp)) { func = config.ConversionOverride[bp]; } if (isNonSurjective) { func.AddToModel(Model, relicBase[s, e, bp], cv, SolverConfig.SolverSupportsSOS); } Model.AddConstraint(cv <= remCap * gv, $"upper stat cap for {bp} of relic {e} in slot {s}"); StatExprs.AddExprToDict(bp, cv); } }
private void CreateRelicModel(EquipSlot s, Equipment e) { var gv = gear[s, e]; var eCap = RelicCaps[e]; Model.AddConstraint(Expression.Sum(RelevantStats.Select(bp => cap[s, e, bp])) <= eCap * gv, $"total relic cap for {e} in slot {s}"); foreach (var bp in RelevantStats) { var remCap = e.GetMateriaMeldCap(bp, true); if (remCap == 0) { continue; } var cv = cap[s, e, bp]; Model.AddConstraint(cv <= remCap * gv, $"upper stat cap for {bp} of relic {e} in slot {s}"); AddExprToDict(StatExprs, bp, cv); // SIMPLIFICATION: impossible-to-reach stat values are ignored. Can be handled by using Model.AddAlternativeConstraint(cv <= badVal - 1, cv >= badVal +1, bigM) } }