/// <summary> /// Returns a list of possible Recipes that a given character is able to craft. /// </summary> /// <param name="carrier">Probably the player character.</param> /// <returns>A list of possible recipes. Keep it, and invoke Apply on the player's choice.</returns> public static List <Recipe> GetPossibilities(Character carrier) { Carrier = carrier; ItemsToWorkWith = Carrier.GetToken("items"); var results = new List <Recipe>(); var tml = Mix.GetTokenTree("crafting.tml"); foreach (var recipe in tml) { var considered = new List <Token>(); var resultName = "?"; if (recipe.HasToken("produce")) { resultName = recipe.GetToken("produce").Text; } var resultingSourceItem = default(InventoryItem); var steps = recipe.Tokens; var stepRefs = new Token[steps.Count()]; var i = 0; var newRecipe = new Recipe(); foreach (var step in steps) { if (step.Name == "consume" || step.Name == "require") { var amount = 1; if (step.HasToken("amount")) { amount = (int)step.GetToken("amount").Value; } var numFound = 0; if (step.Text == "<anything>") { foreach (var carriedItem in ItemsToWorkWith.Tokens) { var knownItem = NoxicoGame.KnownItems.Find(ki => ki.ID == carriedItem.Name); if (knownItem == null) { Program.WriteLine("Crafting: don't know what a {0} is.", carriedItem.Name); continue; } var withs = step.GetAll("with"); var withouts = step.GetAll("withouts"); var okay = 0; foreach (var with in withs) { if (knownItem.HasToken(with.Text)) { okay++; } } foreach (var without in withouts) { if (knownItem.HasToken(without.Text)) { okay = 0; } } if (okay < withs.Count()) { continue; } if (carriedItem.HasToken("charge")) { numFound += (int)carriedItem.GetToken("charge").Value; } else { numFound++; } stepRefs[i] = carriedItem; if (i == 0) { resultingSourceItem = knownItem; } } } else if (step.Text == "book") { //TODO: see if a book with the given ID is marked as read. } else { foreach (var carriedItem in ItemsToWorkWith.Tokens.Where(t => t.Name == step.Text)) { var knownItem = NoxicoGame.KnownItems.Find(ki => ki.ID == carriedItem.Name); if (knownItem == null) { Program.WriteLine("Crafting: don't know what a {0} is.", carriedItem.Name); continue; } if (carriedItem.HasToken("charge")) { numFound += (int)carriedItem.GetToken("charge").Value; } else { numFound++; } stepRefs[i] = carriedItem; if (i == 0) { resultingSourceItem = knownItem; } } } if (numFound < amount) { Program.WriteLine("Crafting: not enough {0} to craft {1}.", step.Text, resultName); break; } if (step.Name == "consume") { newRecipe.Actions.Add(new CraftConsumeItemAction() { Target = stepRefs[i] }); } } else if (step.Name == "produce") { var itemMade = new Token(step.Text); itemMade.Tokens.AddRange(step.Tokens); newRecipe.Actions.Add(new CraftProduceItemAction() { Target = itemMade }); var resultingKnownItem = NoxicoGame.KnownItems.Find(ki => ki.ID == itemMade.Name); newRecipe.Display = i18n.Format("craft_produce_x_from_y", resultingKnownItem.ToString(itemMade), resultingSourceItem.ToString(stepRefs[0])); } else if (step.Name == "train") { newRecipe.Actions.Add(new CraftTrainAction() { Trainee = carrier, Target = step }); } } if (newRecipe.Display.IsBlank()) { continue; } if (results.Exists(x => x.Display == newRecipe.Display)) { continue; } results.Add(newRecipe); } //Find dyes foreach (var maybeDye in ItemsToWorkWith.Tokens) { var knownItem = NoxicoGame.KnownItems.Find(ki => ki.ID == maybeDye.Name); if (knownItem == null) { Program.WriteLine("Crafting: don't know what a {0} is.", maybeDye.Name); continue; } if (knownItem.HasToken("dye")) { var dyeItem = maybeDye; var color = dyeItem.GetToken("color").Text; foreach (var carriedItem in ItemsToWorkWith.Tokens) { knownItem = NoxicoGame.KnownItems.Find(ki => ki.ID == carriedItem.Name); if (knownItem == null) { Program.WriteLine("Crafting: don't know what a {0} is.", carriedItem.Name); continue; } if (knownItem.HasToken("colored") && !knownItem.HasToken("dye")) { var newRecipe = new Recipe(); newRecipe.Display = i18n.Format("craft_dye_x_y", knownItem.ToString(carriedItem), color); if (!carriedItem.HasToken("color")) { newRecipe.Actions.Add(new CraftAddTokenAction() { Target = carriedItem, Add = new Token("color", 0, color) }); } else if (carriedItem.GetToken("color").Text == color) { continue; } else { newRecipe.Actions.Add(new CraftChangeTokenAction() { Target = carriedItem.GetToken("color"), NewText = color, NewValue = 0 }); } results.Add(newRecipe); } } } } return(results); }