From 06eea0aa48ed763af2bb797f2b1eaa7b9a130347 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Wed, 20 May 2015 18:07:39 -0700 Subject: [PATCH] Add support for conditional recipes --- src/coffee/models/mod_version.coffee | 2 + .../mod_version_parser_v1.coffee | 28 +++++++++++-- src/coffee/models/recipe.coffee | 17 ++++++++ test/mod_version.test.coffee | 5 +++ .../mod_version_parser_v1.test.coffee | 39 +++++++++++++++++++ 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/coffee/models/mod_version.coffee b/src/coffee/models/mod_version.coffee index 73c59bfbd..ae9bb91b0 100644 --- a/src/coffee/models/mod_version.coffee +++ b/src/coffee/models/mod_version.coffee @@ -144,6 +144,8 @@ module.exports = class ModVersion extends BaseModel otherRecipes = [] for recipe in _.values @_recipes + continue unless recipe.isConditionSatisfied() + if recipe.itemSlug.matches itemSlug primaryRecipes.push recipe else if recipe.produces itemSlug diff --git a/src/coffee/models/parser_versions/mod_version_parser_v1.coffee b/src/coffee/models/parser_versions/mod_version_parser_v1.coffee index ecfc88523..678ba87c3 100644 --- a/src/coffee/models/parser_versions/mod_version_parser_v1.coffee +++ b/src/coffee/models/parser_versions/mod_version_parser_v1.coffee @@ -70,6 +70,21 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase for name in inputNames @_recipeData.input.push @_parseStack name + _command_onlyIf: (condition)-> + words = condition.split ' ' + if words.length < 2 then throw new Error 'condition must include a verb followed by a noun' + + inverted = false + if words[0] is 'not' + inverted = true + words.shift() + + verb = words[0] + noun = words[1..].join ' ' + + if not (verb in ['item', 'mod']) then throw new Error "unknown verb: #{verb}" + @_recipeData.condition = verb:verb, noun:noun, inverted:inverted + _command_pattern: (pattern='')-> if not @_recipeData? then throw new Error 'cannot declare "pattern" before "recipe"' if @_recipeData.pattern? then throw new Error 'duplicate declaration of "pattern"' @@ -155,10 +170,11 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase if not recipeData.pattern? then throw new Error 'the "pattern" declaration is required' recipe = new Recipe - input: @_buildStackList modVersion, recipeData.input, recipeData.pattern - output: @_buildStackList modVersion, recipeData.output - pattern: recipeData.pattern - tools: @_buildStackList modVersion, recipeData.tools + condition: recipeData.condition + input: @_buildStackList modVersion, recipeData.input, recipeData.pattern + output: @_buildStackList modVersion, recipeData.output + pattern: recipeData.pattern + tools: @_buildStackList modVersion, recipeData.tools modVersion.addRecipe recipe return recipe @@ -274,6 +290,10 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase builder .line 'recipe:' .indent() + .onlyIf recipe.condition?, => + builder.push 'onlyIf: ' + .onlyIf recipe.condition.inverted, -> builder.push 'not ' + .line recipe.condition.verb, ' ', recipe.condition.noun .onlyIf extraOutputs.length > 0, => builder .push 'extras: ' diff --git a/src/coffee/models/recipe.coffee b/src/coffee/models/recipe.coffee index 800b9c111..b355e2206 100644 --- a/src/coffee/models/recipe.coffee +++ b/src/coffee/models/recipe.coffee @@ -28,6 +28,7 @@ module.exports = class Recipe extends BaseModel attributes.pattern = @_parsePattern attributes.pattern + attributes.condition ?= null attributes.modVersion ?= null attributes.tools ?= [] options.logEvents ?= false @@ -114,6 +115,22 @@ module.exports = class Recipe extends BaseModel return total + isConditionSatisfied: (modPack)-> + return true unless @condition + modPack ?= @modVersion?.mod?.modPack + + result = false + if @condition.verb is 'item' + if modPack?.findItemByName(@condition.noun)? + result = true + else if @condition.verb is 'mod' + modPack.eachMod (mod)-> + if mod.name is @condition.noun + result = true + + if @condition.inverted then result = not result + return result + isPassThroughFor: (itemSlug)-> amountCreated = 0 for stack in @output diff --git a/test/mod_version.test.coffee b/test/mod_version.test.coffee index 7a52b8a60..a5dd36b61 100644 --- a/test/mod_version.test.coffee +++ b/test/mod_version.test.coffee @@ -87,6 +87,7 @@ describe 'mod_version.coffee', -> item: Cake recipe:; input: Milk, Sugar, Egg, Wheat; pattern: 000 121 333; extras: 3 Bucket recipe:; input: Milk, Cocoa Beans, Egg, Wheat; pattern: 000 121 333; extras: 3 Bucket + recipe:; input: Cake Slice; pattern: 000 000 000; onlyIf: item Cake Slice item: Bucket recipe:; input: Iron Ingot; pattern: ... 0.0 .0. """ @@ -94,3 +95,7 @@ describe 'mod_version.coffee', -> it 'finds all recipes which list item as output', -> recipes = modVersion.findRecipes ItemSlug.slugify('test__bucket') (r.output[0].itemSlug.item for r in recipes).sort().should.eql ['bucket', 'cake', 'cake'] + + it 'skip recipes whose conditions are not met', -> + recipes = modVersion.findRecipes ItemSlug.slugify 'test__cake' + recipes.length.should.equal 2 diff --git a/test/parser_versions/mod_version_parser_v1.test.coffee b/test/parser_versions/mod_version_parser_v1.test.coffee index 1f7e9408d..611e57caf 100644 --- a/test/parser_versions/mod_version_parser_v1.test.coffee +++ b/test/parser_versions/mod_version_parser_v1.test.coffee @@ -158,6 +158,40 @@ describe 'mod_version_parser_v1.coffee', -> func = -> parser.parse 'item:Bravo; quantity:12; recipe:;' expect(func).to.throw Error, 'cannot declare "quantity" before "recipe"' + describe 'onlyIf', -> + + beforeEach -> + baseText = 'item: Charlie; recipe:; input:Alpha; pattern:...0.0...; ' + + it 'understands the "item" verb', -> + modVersion = parser.parse baseText + 'onlyIf: item Iron Ingot' + recipes = [] + modVersion.eachRecipe (recipe)-> recipes.push recipe + recipe = recipes[0] + recipe.condition.should.eql verb:'item', noun:'Iron Ingot', inverted:false + + it 'understands the "mod" verb', -> + modVersion = parser.parse baseText + 'onlyIf: mod BuildCraft' + recipes = [] + modVersion.eachRecipe (recipe)-> recipes.push recipe + recipe = recipes[0] + recipe.condition.should.eql verb:'mod', noun:'BuildCraft', inverted:false + + it 'understands inverting verbs', -> + modVersion = parser.parse baseText + 'onlyIf: not item Iron Ingot' + recipes = [] + modVersion.eachRecipe (recipe)-> recipes.push recipe + recipe = recipes[0] + recipe.condition.should.eql verb:'item', noun:'Iron Ingot', inverted:true + + it 'requires at least two words', -> + func = -> parser.parse baseText + 'onlyIf: item' + expect(func).to.throw Error, 'verb followed by a noun' + + it 'only allows known verbs', -> + func = -> parser.parse baseText + 'onlyIf: foo Iron Ingot' + expect(func).to.throw Error, 'unknown verb' + describe 'output', -> beforeEach -> @@ -250,6 +284,11 @@ describe 'mod_version_parser_v1.coffee', -> input: furnace fuel, Iron Dust pattern: .1. ... .0. tools: Furnace + recipe: + onlyIf: item Redstone Furnace + input: Iron Ore + pattern: ... .0. ... + tools: Redstone Furnace """ it 'can round-trip a data file', ->