public static Gem Base(int Color) { Gem b = new Gem(); b.Grade = 0; b.Cost = 1; b.damage = 0; // gems that needs damage will have that properly setted (dmg_yellow=1) if (Color == COLOR_BLACK) { b.damage = 1.186168; b.blood = 1.0; } else if (Color == COLOR_KILLGEM) { b.damage = 1.0; b.critMult = 1.0; b.blood = 1.0; } else if (Color == COLOR_MANAGEM) { b.leech = 1.0; b.blood = 1.0; } else if (Color == COLOR_ORANGE) b.leech = 1.0; else if (Color == COLOR_YELLOW) { b.damage = 1.0; b.critMult = 1.0; } else if (Color == COLOR_RED) b.damage = 0.909091; return b; }
/// <summary>Initializes a new instance of the <see cref="Preset"/> class from the files specified in the passed resource.resx, and adds the information to the presets.</summary> /// <param name="letters">The list of letters that go into the gem (e.g., "obr").</param> /// <param name="name">The friendly name of the group, for display purposes.</param> /// <param name="embeddedResourceFullName">Full path to the embedded assembly resource file containing the schemes</param> public Preset(string letters, string name, string embeddedResourceFullName) { ThrowNull(letters, nameof(letters)); ThrowNull(name, nameof(name)); ThrowNull(embeddedResourceFullName, nameof(embeddedResourceFullName)); this.Name = name; using (ResourceReader resourceReader = new ResourceReader(assembly.GetManifestResourceStream(embeddedResourceFullName))) { var dict = resourceReader.GetEnumerator(); while (dict.MoveNext()) { var gemCombines = new List<Instruction>(); using (MemoryStream memoryStream = new MemoryStream((byte[])dict.Value)) using (BinaryReader binaryStream = new BinaryReader(memoryStream)) { while (memoryStream.Position < memoryStream.Length) { gemCombines.Add(Instruction.NewFromStream(binaryStream)); } } List<Gem> gems = new List<Gem>(); gems.Add(null); for (int i = 0; i < gemCombines[0].From; i++) { gems.Add(new Gem(letters[i])); } Gem lastGem = null; for (int i = 1; i < gemCombines.Count; i++) { var combine = gemCombines[i]; Gem c1 = gems[combine.From]; Gem c2 = gems[combine.To]; lastGem = new Gem(c1, c2); gems.Add(lastGem); } this.Entries.Add(lastGem); } } }
private void SetGems(string str) { combined.Clear(); useCount.Clear(); // Add baseGems to combined, and add values for their useage count. combined.Add(null); useCount.Add(-1); for (int i = 0; i < baseGems.Count; i++) { combined.Add(baseGems[i]); combined[i + 1].strID = (i + 1).ToString(); useCount.Add(0); } do { // Get the first set of parenthesis and replace with incrementing id. int close = str.IndexOf(')'); if (close == -1) break; int open = str.LastIndexOf('(', close); string thisCombine = str.Substring(open + 1, close - open - 1); string[] cGems = thisCombine.Split('+'); int gem1 = Convert.ToInt32(cGems[0]); int gem2 = Convert.ToInt32(cGems[1]); str = str.Replace("(" + gem1 + "+" + gem2 + ")", combined.Count.ToString()); // Internal combines resultGem = Gem.Combine(combined[gem1], combined[gem2]); resultGem.strID = combined.Count.ToString(); combined.Add(resultGem); useCount.Add(0); // Have to track times each gem is used. useCount[gem1]++; useCount[gem2]++; } while (true); // final combine if (str.Contains('+')) { // if scheme was surrounded by parenthesis (e.g. ((1+1)+1)) this step is not required, was already done in loop. string[] lastGems = str.Split('+'); int fgem1 = Convert.ToInt32(lastGems[0]); int fgem2 = Convert.ToInt32(lastGems[1]); resultGem = Gem.Combine(combined[fgem1], combined[fgem2]); resultGem.strID = combined.Count.ToString(); combined.Add(resultGem); useCount.Add(0); useCount[fgem1]++; useCount[fgem2]++; } orderedCombined = new List<Gem>(); orderedCombined.AddRange(combined); }
private int GetEmpty(Gem[] a) { for (int i = 0; i < a.Length; i++) { if (a[i] == null) return i; } return -1; }
private void CreateInstructions() { inst.Clear(); // Instructions list Gem[] inventory = new Gem[136]; // Array of what is in each of your inventory slots (Over 36 because this is before slot compression.) int[] slots = new int[combined.Count]; // Which slot each gem is in for (int i = 0; i < slots.Length; i++) slots[i] = -2; // Place baseGems in inventory slots for (int i = 0; i < baseGems.Count; i++) { inventory[i] = combined[i + 1]; slots[i + 1] = i; } Slots_Required = 0; // All oneUse stuff is for slot compression. (This part of slot compression works.) List<int> oneUse = new List<int>(); int startAt = baseGems.Count + 1; // Don't try to give instructinos for placing the base gems. for (int i = startAt; i < combined.Count; i++) { Gem g = combined[i]; int c1 = Convert.ToInt32(g.Component1.strID); int c2 = Convert.ToInt32(g.Component2.strID); int slot1 = slots[c1]; int slot2 = slots[c2]; if (c1 == c2) { // Upgrade gem useCount[c2] -= 2; if (useCount[c2] > 0) { // DUPE inst.Add(new Point(slot1, INST_DUPE)); slots[c1] = GetEmpty(inventory); inventory[slots[c1]] = g.Component1; CheckSlotReq(slots[c1]); } inst.Add(new Point(slot1, INST_UPGR)); inventory[slot1] = g; slots[Convert.ToInt32(g.strID)] = slot1; } else { if (useCount[c1] > 1) { // DUPE inst.Add(new Point(slot1, INST_DUPE)); slots[c1] = GetEmpty(inventory); inventory[slots[c1]] = g.Component1; CheckSlotReq(slots[c1]); } if (useCount[c2] > 1) { // DUPE (repetitive code :/) inst.Add(new Point(slot2, INST_DUPE)); slots[c2] = GetEmpty(inventory); inventory[slots[c2]] = g.Component1; CheckSlotReq(slots[c2]); } useCount[c1] -= 1; useCount[c2] -= 1; if (useCount[c1] == 1) oneUse.Add(c1); if (useCount[c2] == 1) oneUse.Add(c2); inst.Add(new Point(slot1, slot2)); inventory[slot1] = null; inventory[slot2] = g; slots[Convert.ToInt32(g.strID)] = slot2; // None remaining? (Did not dupe) // useCount[c1] == 0 should work here? if (slots[c1] == slot1) slots[c1] = -1; if (slots[c2] == slot2) slots[c2] = -1; // Check oneUse combines for (int iU = i + 2; iU < combined.Count; iU++) { Gem gU = combined[iU]; int c1U = Convert.ToInt32(gU.Component1.strID); int c2U = Convert.ToInt32(gU.Component2.strID); int slot1U = slots[c1U]; int slot2U = slots[c2U]; int oneID1 = oneUse.IndexOf(c1U); int oneID2 = oneUse.IndexOf(c2U); if (oneID1 != -1 && oneID2 != -1) { // Combine, by shifting position in combined list. combined.Insert(i + 1, combined[iU]); combined.RemoveAt(iU + 1); oneUse.RemoveAt(oneID1); oneUse.Remove(c2U); iU -= 2; } else if (GetEmpty(inventory) < Slots_Required && oneID1 != -1 && slot2U > 0) { // If only one of the two is a oneUse, combine it anyway, if doing so will not put it over the current Slots_Req combined.Insert(i + 1, combined[iU]); combined.RemoveAt(iU + 1); oneUse.RemoveAt(oneID1); iU--; } else if (GetEmpty(inventory) < Slots_Required && oneID2 != -1 && slot1U > 0) { combined.Insert(i + 1, combined[iU]); combined.RemoveAt(iU + 1); oneUse.RemoveAt(oneID2); iU--; } } } } // REDUCE SLOT REQUIREMENT if (limitSlots && Slots_Required > 36) { inst = CondenseSlots(resultGem, inst, false, 36); inst.Insert(0, new Point(0, -36)); } }
// CondenseSlots seems to be messed up, I can't get the 262144-combine to work. private List<Point> CondenseSlots(Gem g, List<Point> bigInst, bool keepBase, int slotLimit) { // Get the combine INST for both components. (Will not include duplicating base gem.) // If the combine for a component exceeds the slotLimit, CondenseSlots to get new INST. // // Each component's combine INST must include placing the base gem in slot 0. // If I add the duplicate step to p1.inst, then the new condensed one will already have it. // To solve this, try: If the INST does not begin with duplicate step, add it. Gem c1 = g.Component1; Gem c2 = g.Component2; CombinePerformer p1 = new CombinePerformer(); p1.limitSlots = false; p1.SetMethod(c1.GetFullCombine()); p1.resultGem.strID = c1.strID; CombinePerformer p2 = new CombinePerformer(); p2.limitSlots = false; p2.SetMethod(c2.GetFullCombine()); p2.resultGem.strID = c2.strID; if (p1.Slots_Required > slotLimit - 1) p1.inst = CondenseSlots(c1, p1.inst, true, slotLimit); // Move result gem to highest open slot p1.inst.Add(new Point(p1.inst.Last().Y, -(slotLimit - 1))); // Move to 1st open space. if (p2.Slots_Required > slotLimit - 1) p2.inst = CondenseSlots(c2, p2.inst, false, slotLimit - 1); if (keepBase) // Is slot 36 used by baseGem? p2.inst.Add(new Point(p2.inst.Last().Y, -(slotLimit - 2))); // 2nd open (now 1st) space. else p2.inst.Add(new Point(p2.inst.Last().Y, -36)); List<Point> newInst = new List<Point>(); // Both combines require placing a base gem in slot 0 first. if (p1.inst[0].X != 35) newInst.Add(new Point(35, INST_DUPE)); newInst.AddRange(p1.inst); if (keepBase || p2.Slots_Required > slotLimit - 1) // Duplicate base_gem newInst.Add(new Point(35, INST_DUPE)); else // Move base_gem newInst.Add(new Point(35, -1)); newInst.AddRange(p2.inst); // Combine the two resulting gems if (keepBase) newInst.Add(new Point((slotLimit - 3), (slotLimit - 2))); // Combine to the higher slot (shouldn't matter, last gem is moved later anyway) else newInst.Add(new Point((slotLimit - 2), 35)); // Finally return newInst; }
private static string GetListName(Gem gem) => GetColorName(gem.Color) + " " + gem.SpecWord;
private void BuildGem(Gem gem, InstructionCollection instructions, bool doPostScan) { if (gem == null || !gem.IsNeeded || instructions.SlotsRequired > SlotLimit) { return; } var gem1 = gem.Component1; var gem2 = gem.Component2; this.BuildGem(gem1, instructions, true); this.BuildGem(gem2, instructions, true); // Re-check if gem is needed in case gem was already built during optimization routine for component gems. if (gem.IsNeeded && instructions.SlotsRequired <= SlotLimit) { gem1.UseCount--; gem2.UseCount--; doPostScan &= gem.IsUpgrade ? instructions.Upgrade(gem) : instructions.Combine(gem); while (doPostScan && instructions.SlotsRequired <= SlotLimit) { doPostScan = this.OptimizeLastGems(instructions) || this.OptimizeSingleUseGems(instructions); } } }
private Combiner(Gem parentGem, IReadOnlyList<Gem> gemList, bool lastRun) { ThrowNull(parentGem, nameof(parentGem)); ThrowNull(gemList, nameof(gemList)); this.Gem = parentGem; // Only update UseCount for gems actually used in this combiner. // First, determine which gems are actually part of this combine. Hijacking UseCount as a marker, since we're going to be resetting it right after this anyway (and those in the base list don't matter anymore). foreach (var gem in gemList) { gem.UseCount = 0; } this.Gem.UseCount = -1; bool changesMade; do { changesMade = false; for (int i = gemList.Count - 1; i >= 0; i--) { var gem = gemList[i]; if (gem.UseCount == -1 && !(gem is BaseGem)) { foreach (var component in gem) { if (component.UseCount != -1) { changesMade = true; component.UseCount = -1; } } } } } while (changesMade); this.gems = new List<Gem>(); foreach (var gem in gemList) { if (gem.UseCount == -1) { this.gems.Add(gem); } } this.ResetUseCount(!lastRun); }
private string GetGemInfo(Gem g) { return "Grade +" + g.Grade + "\n" + ("Cost: " + g.Cost + "x\n") + //("Power: " + Math.Round(g.Power, 6) + "\n") + ("Growth: " + Math.Round(g.Growth, 6) + " "); // [ie] need accuracy to 6 for tests //("Damage: " + Math.Round(g.damage, 6) + "\n") + //("Leech: " + Math.Round(g.leech, 6) + "\n") + //("Crit: " + Math.Round(g.critMult, 6) + "\n") + //("Bbound: " + Math.Round(g.blood, 6) + ""); }
public InstructionCollection(InstructionCollection instructions1, InstructionCollection instructions2, Gem combine) { ThrowNull(instructions1, nameof(instructions1)); ThrowNull(instructions2, nameof(instructions2)); this.instructions.AddRange(instructions1); this.instructions.AddRange(instructions2); this.Combine(combine); this.SlotsRequired = instructions2.SlotsRequired > instructions1.SlotsRequired ? instructions2.SlotsRequired : instructions1.SlotsRequired; }
public static Gem Combine(Gem g1, Gem g2) { Gem ret = new Gem(); if (g2.Cost > g1.Cost) { ret.Component1 = g2; ret.Component2 = g1; } else { ret.Component1 = g1; ret.Component2 = g2; } if (g1.Grade == g2.Grade) { ret.Grade = g1.Grade + 1; ret.damage = g1.damage > g2.damage ? 0.87 * g1.damage + 0.71 * g2.damage : 0.87 * g2.damage + 0.71 * g1.damage; ret.leech = g1.leech > g2.leech ? 0.88 * g1.leech + 0.50 * g2.leech : 0.88 * g2.leech + 0.50 * g1.leech; ret.blood = g1.blood > g2.blood ? 0.78 * g1.blood + 0.31 * g2.blood : 0.78 * g2.blood + 0.31 * g1.blood; ret.critMult = g1.critMult > g2.critMult ? 0.88 * g1.critMult + 0.50 * g2.critMult : 0.88 * g2.critMult + 0.50 * g1.critMult; } else if (g1.Grade == g2.Grade + 1) { ret.Grade = g1.Grade; ret.damage = g1.damage > g2.damage ? 0.86 * g1.damage + 0.70 * g2.damage : 0.86 * g2.damage + 0.70 * g1.damage; ret.leech = g1.leech > g2.leech ? 0.89 * g1.leech + 0.44 * g2.leech : 0.89 * g2.leech + 0.44 * g1.leech; ret.blood = g1.blood > g2.blood ? 0.79 * g1.blood + 0.29 * g2.blood : 0.79 * g2.blood + 0.29 * g1.blood; ret.critMult = g1.critMult > g2.critMult ? 0.88 * g1.critMult + 0.44 * g2.critMult : 0.88 * g2.critMult + 0.44 * g1.critMult; } else if (g1.Grade == g2.Grade - 1) { ret.Grade = g2.Grade; ret.damage = g1.damage > g2.damage ? 0.86 * g1.damage + 0.70 * g2.damage : 0.86 * g2.damage + 0.70 * g1.damage; ret.leech = g1.leech > g2.leech ? 0.89 * g1.leech + 0.44 * g2.leech : 0.89 * g2.leech + 0.44 * g1.leech; ret.blood = g1.blood > g2.blood ? 0.79 * g1.blood + 0.29 * g2.blood : 0.79 * g2.blood + 0.29 * g1.blood; ret.critMult = g1.critMult > g2.critMult ? 0.88 * g1.critMult + 0.44 * g2.critMult : 0.88 * g2.critMult + 0.44 * g1.critMult; } else { ret.Grade = g1.Grade; if (g2.Grade > g1.Grade) ret.Grade = g2.Grade; ret.damage = g1.damage > g2.damage ? 0.85 * g1.damage + 0.69 * g2.damage : 0.85 * g2.damage + 0.69 * g1.damage; ret.leech = g1.leech > g2.leech ? 0.90 * g1.leech + 0.38 * g2.leech : 0.90 * g2.leech + 0.38 * g1.leech; ret.blood = g1.blood > g2.blood ? 0.80 * g1.blood + 0.27 * g2.blood : 0.80 * g2.blood + 0.27 * g1.blood; ret.critMult = g1.critMult > g2.critMult ? 0.88 * g1.critMult + 0.44 * g2.critMult : 0.88 * g2.critMult + 0.44 * g1.critMult; } ret.damage = Math.Max(ret.damage, g1.damage); ret.damage = Math.Max(ret.damage, g2.damage); ret.Cost = ret.Component1.Cost + ret.Component2.Cost; ret.Growth = Math.Log10(ret.Power) / Math.Log10(ret.Cost); return ret; }