Allow item stacks as input for recipes

* Create the SlotController and refactor it into the various places
  where a crafting grid or crafting output is displayed
* Update the Recipe model to allow each "input" stack to retain the
  count indicated in the data file. This required changing how a few
  other classes interact with it in order for them to get the full
  stack back again for each input (instead of just getting the item
  slug)
* Update the ModVersionParser to allow for full stacks to be given
  as input and refactored common code out for handling input/output/
  tools stacks
This commit is contained in:
Andrew Miner
2015-04-07 19:21:02 -07:00
parent 2ba4dca95b
commit 144aa1bf32
17 changed files with 244 additions and 3426 deletions
@@ -6,9 +6,10 @@ All rights reserved.
### ###
BaseController = require './base_controller' BaseController = require './base_controller'
ImageLoader = require './image_loader'
SlotController = require './slot_controller'
{Duration} = require '../constants' {Duration} = require '../constants'
{Event} = require '../constants' {Event} = require '../constants'
ImageLoader = require './image_loader'
######################################################################################################################## ########################################################################################################################
@@ -17,58 +18,29 @@ module.exports = class CraftingGridController extends BaseController
constructor: (options={})-> constructor: (options={})->
if not options.imageLoader? then throw new Error 'options.imageLoader is required' if not options.imageLoader? then throw new Error 'options.imageLoader is required'
if not options.modPack? then throw new Error 'options.modPack is required' if not options.modPack? then throw new Error 'options.modPack is required'
# options.model should be a recipe
options.templateName = 'crafting_grid' options.templateName = 'crafting_grid'
super options super options
@_imageLoader = options.imageLoader @imageLoader = options.imageLoader
@_modPack = options.modPack @modPack = options.modPack
@_slotCount = 9
@_modPack.on Event.change, => @tryRefresh() @modPack.on Event.change, => @tryRefresh()
# BaseController Methods ####################################################################### # BaseController Methods #######################################################################
onDidRender: -> onDidRender: ->
@slots = [] @slotControllers = []
for el in @$('td') for el in @$('.view__slot')
$el = $(el) controller = new SlotController el:el, imageLoader:@imageLoader, modPack:@modPack
@slots.push a:$el.find('a'), img:$el.find('img') controller.render()
@slotControllers.push controller
super super
refresh: -> refresh: ->
for index in [0...@slots.length] for i in [0...@slotControllers.length]
slot = @slots[index] controller = @slotControllers[i]
controller.model = @model?.getStackAtSlot(i)
slot.a.addClass 'empty'
slot.a.removeAttr 'href'
slot.img.attr 'src', '/images/empty.png'
slot.img.removeAttr 'alt'
display = @_getItemDisplayAt index
if display?
slot.a.removeClass 'empty'
slot.a.attr 'href', display.itemUrl
slot.a.attr 'title', display.itemName
@_imageLoader.load display.iconUrl, slot.img
slot.img.attr 'alt', display.itemName
@$el.tooltip show:{delay:Duration.snap, duration:Duration.fast} @$el.tooltip show:{delay:Duration.snap, duration:Duration.fast}
super super
# Backbone.View Overrides ######################################################################
events: ->
return _.extend super,
'click td a': 'routeLinkClick'
# Private Methods ##############################################################################
_getItemDisplayAt: (slot)->
if slot >= @_slotCount then throw new Error "slot (#{slot}) must be less than #{@_slotCount}"
return null unless @model?
itemSlug = @model.getItemSlugAt slot
return null unless itemSlug?
itemDisplay = @_modPack.findItemDisplay itemSlug
return itemDisplay
@@ -30,8 +30,8 @@ module.exports = class FullRecipeController extends BaseController
onDidRender: -> onDidRender: ->
@gridController = @addChild CraftingGridController, '.view__crafting_grid', @gridController = @addChild CraftingGridController, '.view__crafting_grid',
modPack: @modPack
imageLoader: @imageLoader imageLoader: @imageLoader
modPack: @modPack
@inputController = @addChild InventoryTableController, '.input .view__inventory_table', @inputController = @addChild InventoryTableController, '.input .view__inventory_table',
editable: false editable: false
@@ -72,7 +72,7 @@ module.exports = class FullRecipeController extends BaseController
inputs.clear() inputs.clear()
if @model? if @model?
for stack in @model.input @model.eachInputStack (stack)->
inputs.add stack.itemSlug, stack.quantity inputs.add stack.itemSlug, stack.quantity
@@ -8,6 +8,7 @@ All rights reserved.
BaseController = require './base_controller' BaseController = require './base_controller'
CraftingGridController = require './crafting_grid_controller' CraftingGridController = require './crafting_grid_controller'
ImageLoader = require './image_loader' ImageLoader = require './image_loader'
SlotController = require './slot_controller'
{Duration} = require '../constants' {Duration} = require '../constants'
{StringBuilder} = require 'crafting-guide-common' {StringBuilder} = require 'crafting-guide-common'
@@ -31,6 +32,10 @@ module.exports = class MinimalRecipeController extends BaseController
modPack: @modPack modPack: @modPack
imageLoader: @imageLoader imageLoader: @imageLoader
@outputSlotController = @addChild SlotController, '.output.view__slot',
imageLoader: @imageLoader
modPack: @modPack
@$outputImg = @$('.output img') @$outputImg = @$('.output img')
@$outputLink = @$('.output a') @$outputLink = @$('.output a')
@$outputQuantity = @$('.quantity') @$outputQuantity = @$('.quantity')
@@ -39,25 +44,8 @@ module.exports = class MinimalRecipeController extends BaseController
refresh: -> refresh: ->
@gridController.model = @model @gridController.model = @model
@outputSlotController.model = @model?.output?[0]
@$outputImg.attr 'src', '/images/empty.png'
@$outputImg.removeAttr 'alt'
@$outputLink.removeAttr 'href'
@$outputQuantity.html ''
if @model?
outputStack = @model.output[0]
if outputStack?
display = @modPack.findItemDisplay outputStack.itemSlug
@$outputLink.attr 'href', display.itemUrl
@$outputLink.attr 'title', display.itemName
@$outputImg.attr 'alt', display.itemName
@$outputQuantity.html outputStack.quantity if outputStack.quantity > 1
@imageLoader.load display.iconUrl, @$outputImg
@$el.tooltip show:{delay:Duration.snap, duration:Duration.fast} @$el.tooltip show:{delay:Duration.snap, duration:Duration.fast}
@_refreshTools() @_refreshTools()
super super
@@ -0,0 +1,58 @@
###
Crafting Guide - slot_controller.coffee
Copyright (c) 2015 by Redwood Labs
All rights reserved.
###
BaseController = require './base_controller'
########################################################################################################################
module.exports = class SlotController extends BaseController
constructor: (options={})->
if not options.imageLoader? then throw new Error 'options.imageLoader is required'
if not options.modPack? then throw new Error 'options.modPack is required'
# options.model should be a Stack
options.templateName = 'slot'
options.useAnimations = false
super options
@imageLoader = options.imageLoader
@modPack = options.modPack
# BaseController Overrides #####################################################################
onDidRender: ->
@$link = @$('a')
@$image = @$('img')
@$quantity = @$('.quantity')
super
refresh: ->
if @model?
display = @modPack.findItemDisplay @model.itemSlug
@$link.attr 'href', display.itemUrl
@imageLoader.load display.iconUrl, @$image
@show @$image
if @model.quantity > 1
@$quantity.html @model.quantity
else
@$quantity.html ''
else
@$link.removeAttr 'href'
@$quantity.html ''
@$image.removeAttr 'src'
@hide @$image
super
# Backbone.View Overrides ######################################################################
events: ->
return _.extend super,
'click a': 'routeLinkClick'
+3 -3
View File
@@ -177,7 +177,7 @@ module.exports = class CraftingPlan extends BaseModel
step.multiplier = Math.ceil(@need.quantityOf(step.itemSlug) / recipe.output[0].quantity) step.multiplier = Math.ceil(@need.quantityOf(step.itemSlug) / recipe.output[0].quantity)
if @includingTools if @includingTools
for stack in recipe.tools recipe.eachToolStack (stack)=>
itemSlug = @_qualifyItemSlug stack.itemSlug itemSlug = @_qualifyItemSlug stack.itemSlug
available = @result.quantityOf(itemSlug) + @need.quantityOf(itemSlug) available = @result.quantityOf(itemSlug) + @need.quantityOf(itemSlug)
needed = Math.max 0, stack.quantity - available needed = Math.max 0, stack.quantity - available
@@ -185,7 +185,7 @@ module.exports = class CraftingPlan extends BaseModel
@need.add itemSlug, needed @need.add itemSlug, needed
@result.add itemSlug, needed @result.add itemSlug, needed
for stack in recipe.input recipe.eachInputStack (stack)=>
itemSlug = @_qualifyItemSlug stack.itemSlug itemSlug = @_qualifyItemSlug stack.itemSlug
needed = step.multiplier * stack.quantity needed = step.multiplier * stack.quantity
consumed = Math.min needed, @result.quantityOf itemSlug consumed = Math.min needed, @result.quantityOf itemSlug
@@ -194,7 +194,7 @@ module.exports = class CraftingPlan extends BaseModel
@result.remove itemSlug, consumed @result.remove itemSlug, consumed
@need.add itemSlug, remaining @need.add itemSlug, remaining
for stack in recipe.output recipe.eachOutputStack (stack)=>
itemSlug = @_qualifyItemSlug stack.itemSlug itemSlug = @_qualifyItemSlug stack.itemSlug
created = stack.quantity * step.multiplier created = stack.quantity * step.multiplier
consumed = Math.min created, @need.quantityOf itemSlug consumed = Math.min created, @need.quantityOf itemSlug
@@ -37,15 +37,10 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
_command_extras: (extraTerms...)-> _command_extras: (extraTerms...)->
if not @_recipeData? then throw new Error 'cannot declare "extras" before "recipe"' if not @_recipeData? then throw new Error 'cannot declare "extras" before "recipe"'
if @_recipeData.extras? then throw new Error 'duplicate declaration of "extras"' if @_recipeData.output.length isnt 1 then throw new Error 'duplicate declaration of "extras"'
@_recipeData.extras = []
for term in extraTerms for term in extraTerms
match = ModVersionParserV1.STACK.exec term @_recipeData.output.push @_parseStack term
if match?
@_recipeData.extras.push quantity:parseInt(match[1]), name:match[2]
else
@_recipeData.extras.push quantity:1, name:term
_command_gatherable: (gatherable)-> _command_gatherable: (gatherable)->
if not @_itemData? then throw new Error 'cannot declare "gatherable" before "item"' if not @_itemData? then throw new Error 'cannot declare "gatherable" before "item"'
@@ -69,12 +64,10 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
_command_input: (inputNames...)-> _command_input: (inputNames...)->
if not @_recipeData? then throw new Error 'cannot declare "input" before "recipe"' if not @_recipeData? then throw new Error 'cannot declare "input" before "recipe"'
if @_recipeData.input? then throw new Error 'duplicate declaration of "input"' if @_recipeData.input.length isnt 0 then throw new Error 'duplicate declaration of "input"'
@_recipeData.input = []
for name in inputNames for name in inputNames
if name.length is 0 then throw new Error 'input names cannot be empty' @_recipeData.input.push @_parseStack name
@_recipeData.input.push name
_command_pattern: (pattern='')-> _command_pattern: (pattern='')->
if not @_recipeData? then throw new Error 'cannot declare "pattern" before "recipe"' if not @_recipeData? then throw new Error 'cannot declare "pattern" before "recipe"'
@@ -90,23 +83,23 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
if @_recipeData.quantity? then throw new Error 'duplicate declaration of "quantity"' if @_recipeData.quantity? then throw new Error 'duplicate declaration of "quantity"'
if not ModVersionParserV1.INTEGER.test(quantity) then throw new Error 'quantity must be an integer' if not ModVersionParserV1.INTEGER.test(quantity) then throw new Error 'quantity must be an integer'
@_recipeData.quantity = parseInt quantity @_recipeData.quantity = quantity
@_recipeData.output[0].quantity = parseInt quantity
_command_recipe: -> _command_recipe: ->
if not @_itemData? then throw new Error 'cannot delcare "recipe" before "item"' if not @_itemData? then throw new Error 'cannot delcare "recipe" before "item"'
@_recipeData = line:@_lineNumber @_recipeData = line:@_lineNumber, input:[], output:[{quantity:1, name:@_itemData.name}], tools:[]
@_itemData.recipes ?= [] @_itemData.recipes ?= []
@_itemData.recipes.push @_recipeData @_itemData.recipes.push @_recipeData
_command_tools: (toolNames...)-> _command_tools: (toolNames...)->
if not @_recipeData? then throw new Error 'cannot declare "tools" before "recipe"' if not @_recipeData? then throw new Error 'cannot declare "tools" before "recipe"'
if @_recipeData.tools? then throw new Error 'duplicate declaration of "tools"' if @_recipeData.tools.length isnt 0 then throw new Error 'duplicate declaration of "tools"'
@_recipeData.tools = []
for name in toolNames for name in toolNames
if name.length is 0 then throw new Error 'tool names cannot be empty' if name.length is 0 then throw new Error 'tool names cannot be empty'
@_recipeData.tools.push name @_recipeData.tools.push name:name, quantity:1
_command_update: (name='')-> _command_update: (name='')->
if not name.length > 0 then throw new 'the item name cannot be empty' if not name.length > 0 then throw new 'the item name cannot be empty'
@@ -117,6 +110,15 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
@_rawData.items ?= {} @_rawData.items ?= {}
@_rawData.items[name] = @_itemData @_rawData.items[name] = @_itemData
# Parsing Helpers ##############################################################################
_parseStack: (stackText)->
match = ModVersionParserV1.STACK.exec stackText
if match?
return quantity:parseInt(match[1]), name:match[2]
else
return quantity:1, name:stackText
# Object Creation Methods ###################################################################### # Object Creation Methods ######################################################################
_buildModVersion: (modVersionData, modVersion)-> _buildModVersion: (modVersionData, modVersion)->
@@ -148,9 +150,19 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
_buildRecipe: (modVersion, itemData, recipeData)-> _buildRecipe: (modVersion, itemData, recipeData)->
@_lineNumber = recipeData.line @_lineNumber = recipeData.line
if not recipeData.input? then throw new Error 'the "input" declaration is required' if recipeData.input.length is 0 then throw new Error 'the "input" declaration is required'
if not recipeData.pattern? then throw new Error 'the "pattern" declaration is required' 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
modVersion.addRecipe recipe
return recipe
_buildStackList: (modVersion, data, pattern=null)->
createSlug = (name)=> createSlug = (name)=>
item = @_rawData.items[name] item = @_rawData.items[name]
if item? and item.type isnt 'update' if item? and item.type isnt 'update'
@@ -160,46 +172,26 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
modVersion.registerName slug, name modVersion.registerName slug, name
return slug return slug
recipeData.quantity ?= 1 stacks = []
recipeData.extras ?= [] for stackData in data
recipeData.tools ?= [] itemSlug = createSlug stackData.name
stacks.push new Stack itemSlug:itemSlug, quantity:stackData.quantity
inputStacks = [] if pattern?
for name in recipeData.input expectedIndexes = _.reduce [0...stacks.length], ((obj, i)-> obj[i] = true; return obj), {}
inputSlug = createSlug name for c in pattern
inputStacks.push new Stack itemSlug:inputSlug, quantity:0 continue if c is '.'
continue if c is ' '
delete expectedIndexes[c]
if not stacks[parseInt(c)]? then throw new Error "there is no item #{c} in this recipe"
for c in recipeData.pattern unusedNames = _.map(_.keys(expectedIndexes), ((i)-> data[parseInt(i)].name))
continue if c is '.' if unusedNames.length > 1
continue if c is ' ' throw new Error "#{unusedNames.join(', ')} are listed for this recipe, but do not appear in the pattern"
stack = inputStacks[parseInt(c)] else if unusedNames.length is 1
if not stack? then throw new Error "there is no input #{c} in this recipe" throw new Error "#{unusedNames[0]} is listed for this recipe, but does not appear in the pattern"
stack.quantity += 1
for i in [0...inputStacks.length] return stacks
stack = inputStacks[i]
if stack.quantity is 0
name = modVersion.findName stack.itemSlug
throw new Error "#{name} is an input for this recipe, but it is not in the pattern"
outputStacks = [ new Stack itemSlug:itemData.slug, quantity:recipeData.quantity ]
for extraData in recipeData.extras
outputSlug = createSlug extraData.name
outputStacks.push new Stack itemSlug:outputSlug, quantity:extraData.quantity
toolStacks = []
for name in recipeData.tools
toolSlug = createSlug name
toolStacks.push new Stack itemSlug:toolSlug, quantity:1
recipe = new Recipe
input: inputStacks
output: outputStacks
pattern: recipeData.pattern
tools: toolStacks
modVersion.addRecipe recipe
return recipe
# Un-parsing Methods ########################################################################### # Un-parsing Methods ###########################################################################
@@ -249,13 +241,22 @@ module.exports = class ModVersionParserV1 extends CommandParserVersionBase
.outdent() .outdent()
_unparseRecipe: (builder, recipe)-> _unparseRecipe: (builder, recipe)->
inputNames = (builder.context.findName(stack.itemSlug) for stack in recipe.input) inputStacks = recipe.input[..]
inputNames.sort() inputStacks.sort (a, b)-> Stack.compare a, b
inputNames = []
for stack in inputStacks
name = builder.context.findName stack.itemSlug
if stack.quantity > 1
inputNames.push "#{stack.quantity} #{name}"
else
inputNames.push name
patternMap = {'.', '.'} patternMap = {'.', '.'}
for i in [0...recipe.input.length] for i in [0...recipe.input.length]
stack = recipe.input[i] stack = recipe.input[i]
patternMap["#{i}"] = "#{inputNames.indexOf builder.context.findName(stack.itemSlug)}" name = builder.context.findName(stack.itemSlug)
name = "#{stack.quantity} #{name}" if stack.quantity > 1
patternMap["#{i}"] = "#{inputNames.indexOf name}"
pattern = recipe.pattern or recipe.defaultPattern pattern = recipe.pattern or recipe.defaultPattern
newPattern = [] newPattern = []
+19 -4
View File
@@ -69,13 +69,27 @@ module.exports = class Recipe extends BaseModel
# Public Methods ############################################################################### # Public Methods ###############################################################################
eachInputStack: (callback)->
for i in [0...@pattern.length]
stack = @getStackAtSlot(i)
continue unless stack?
callback stack
eachOutputStack: (callback)->
for stack in @output
callback stack
eachToolStack: (callback)->
for stack in @tools
callback stack
getInputCount: -> getInputCount: ->
result = 0 result = 0
for stack in @input for stack in @input
result += stack.quantity result += stack.quantity
return result return result
getItemSlugAt: (patternSlot)-> getStackAtSlot: (patternSlot)->
trueIndex = 0:0, 1:1, 2:2, 3:4, 4:5, 5:6, 6:8, 7:9, 8:10 trueIndex = 0:0, 1:1, 2:2, 3:4, 4:5, 5:6, 6:8, 7:9, 8:10
patternDigit = @pattern[trueIndex[patternSlot]] patternDigit = @pattern[trueIndex[patternSlot]]
return null unless patternDigit? return null unless patternDigit?
@@ -84,7 +98,7 @@ module.exports = class Recipe extends BaseModel
stack = @input[parseInt(patternDigit)] stack = @input[parseInt(patternDigit)]
return null unless stack? return null unless stack?
return stack.itemSlug return stack
getOutputCount: -> getOutputCount: ->
result = 0 result = 0
@@ -93,11 +107,12 @@ module.exports = class Recipe extends BaseModel
return result return result
getQuantityProducedOf: (itemSlug)-> getQuantityProducedOf: (itemSlug)->
total = 0
for stack in @output for stack in @output
if stack.itemSlug.matches itemSlug if stack.itemSlug.matches itemSlug
return stack.quantity total += stack.quantity
return 0 return total
isPassThroughFor: (itemSlug)-> isPassThroughFor: (itemSlug)->
amountCreated = 0 amountCreated = 0
+11
View File
@@ -5,6 +5,8 @@ Copyright (c) 2014-2015 by Redwood Labs
All rights reserved. All rights reserved.
### ###
ItemSlug = require './item_slug'
######################################################################################################################## ########################################################################################################################
module.exports = class Stack module.exports = class Stack
@@ -16,6 +18,15 @@ module.exports = class Stack
@itemSlug = attributes.itemSlug @itemSlug = attributes.itemSlug
@quantity = attributes.quantity @quantity = attributes.quantity
# Class Methods ################################################################################
@compare: (a, b)->
if a? and not b? then return -1
if not a? and b? then return +1
if a.quantity isnt b.quantity
return if a.quantity > b.quantity then -1 else +1
return ItemSlug.compare a.itemSlug, b.itemSlug
# Object Overrides ############################################################################# # Object Overrides #############################################################################
toString: -> toString: ->
+9 -9
View File
@@ -7,14 +7,14 @@
table.view__crafting_grid table.view__crafting_grid
tr tr
td: a: img(src="/images/empty.png") td: .view__slot
td: a: img(src="/images/empty.png") td: .view__slot
td: a: img(src="/images/empty.png") td: .view__slot
tr tr
td: a: img(src="/images/empty.png") td: .view__slot
td: a: img(src="/images/empty.png") td: .view__slot
td: a: img(src="/images/empty.png") td: .view__slot
tr tr
td: a: img(src="/images/empty.png") td: .view__slot
td: a: img(src="/images/empty.png") td: .view__slot
td: a: img(src="/images/empty.png") td: .view__slot
+1 -3
View File
@@ -9,6 +9,4 @@
.input .input
table.view__crafting_grid table.view__crafting_grid
.tool .tool
.output .output.view__slot
a: img
p.quantity
+11
View File
@@ -0,0 +1,11 @@
//-
//- Crafting Guide - slot.jade
//-
//- Copyright (c) 2015 by Redwood Labs
//- All rights reserved.
//-
.view__slot
a
img.hideable.hiding
.quantity
+1
View File
@@ -26,5 +26,6 @@ All rights reserved.
@import 'mod_page'; @import 'mod_page';
@import 'mod_selector'; @import 'mod_selector';
@import 'stack'; @import 'stack';
@import 'slot';
@import 'tutorial'; @import 'tutorial';
@import 'video'; @import 'video';
+18
View File
@@ -0,0 +1,18 @@
/*
Crafting Guide - slot.scss
Copyright (C) 2015 by Redwood Labs
All rights reserved.
*/
.view__slot {
position: relative;
.quantity {
position: absolute; right: 0.1em; bottom: 0;
color: white;
font-family: $font-family-header;
font-size: $font-size-large;
text-shadow: -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 2px 0 #000;
}
}
File diff suppressed because it is too large Load Diff
@@ -92,8 +92,8 @@ group: Agriculture
item: (Filled) Tin Can item: (Filled) Tin Can
recipe: recipe:
input: Steak, Tin Can input: Steak, 8 Tin Can
pattern: 101 111 111 pattern: .0. ... .1.
quantity: 8 quantity: 8
tools: Canning Machine tools: Canning Machine
recipe: recipe:
@@ -69,10 +69,10 @@ describe 'mod_version_parser_v1.coffee', ->
describe 'input', -> describe 'input', ->
it 'adds "input" when present', -> it 'adds "input" when present', ->
logger.doAtLevel 'DEBUG', -> modVersion = parser.parse baseText + 'recipe:; input:Alpha, Bravo; pattern: ... 010 ...'
modVersion = parser.parse baseText + 'recipe:; input:Alpha, Bravo; pattern: ... 010 ...' charlieSlug = ItemSlug.slugify('test__charlie')
slugs = (s.itemSlug.item for s in modVersion.findRecipes(ItemSlug.slugify('test__charlie'))[0].input) slugs = (s.itemSlug.item for s in modVersion.findRecipes(charlieSlug)[0].input)
slugs.should.eql ['alpha', 'bravo'] slugs.should.eql ['alpha', 'bravo']
it 'requires an "input" declaration', -> it 'requires an "input" declaration', ->
func = -> parser.parse baseText + 'recipe:; pattern: ... .0. ...' func = -> parser.parse baseText + 'recipe:; pattern: ... .0. ...'
@@ -90,6 +90,14 @@ describe 'mod_version_parser_v1.coffee', ->
modVersion = parser.parse baseText + 'recipe:; input:Delta, Echo, Foxtrot; pattern:...012...' modVersion = parser.parse baseText + 'recipe:; input:Delta, Echo, Foxtrot; pattern:...012...'
(s.item for s in modVersion._slugs).should.eql ['charlie', 'delta', 'echo', 'foxtrot'] (s.item for s in modVersion._slugs).should.eql ['charlie', 'delta', 'echo', 'foxtrot']
it 'allows a quantity for each input', ->
modVersion = parser.parse baseText + 'recipe:; input: 12 Delta, 3 Echo; pattern:... 0.1 ...'
recipe = _.values(modVersion._recipes)[0]
recipe.input[0].quantity.should.equal 12
recipe.input[0].itemSlug.qualified.should.equal 'delta'
recipe.input[1].quantity.should.equal 3
recipe.input[1].itemSlug.qualified.should.equal 'echo'
describe 'pattern', -> describe 'pattern', ->
it 'adds "pattern" when present', -> it 'adds "pattern" when present', ->
@@ -114,18 +122,11 @@ describe 'mod_version_parser_v1.coffee', ->
it 'requires pattern to only refer to existing items', -> it 'requires pattern to only refer to existing items', ->
func = -> parser.parse baseText + 'recipe:; input:Alpha; pattern:... 010 ...' func = -> parser.parse baseText + 'recipe:; input:Alpha; pattern:... 010 ...'
expect(func).to.throw Error, 'there is no input 1 in this recipe' expect(func).to.throw Error, 'there is no item 1 in this recipe'
it 'requires all items to appear in the pattern', -> it 'requires all items to appear in the pattern', ->
func = -> parser.parse baseText + 'recipe:; input:Alpha, Bravo; pattern: 000 0.0 000' func = -> parser.parse baseText + 'recipe:; input:Alpha, Bravo; pattern: 000 0.0 000'
expect(func).to.throw Error, 'Bravo is an input' expect(func).to.throw Error, 'Bravo is listed'
it 'computes the input stack sizes from the pattern', ->
modVersion = parser.parse baseText + 'recipe:; input:Alpha, Bravo, Delta; pattern:111 .0. 2.2'
recipe = modVersion.findRecipes(ItemSlug.slugify('test__charlie'))[0]
recipe.input[0].quantity.should.equal 1
recipe.input[1].quantity.should.equal 3
recipe.input[2].quantity.should.equal 2
it 'does not allow "pattern" before "recipe"', -> it 'does not allow "pattern" before "recipe"', ->
func = -> parser.parse baseText + 'pattern:... .0. ...; recipe:; inputs:Alpha' func = -> parser.parse baseText + 'pattern:... .0. ...; recipe:; inputs:Alpha'
@@ -226,10 +227,15 @@ describe 'mod_version_parser_v1.coffee', ->
item: Baked Potato item: Baked Potato
recipe: recipe:
input: Potato, furnace fuel input: furnace fuel, Potato
pattern: .0. ... .1. pattern: .1. ... .0.
tools: Furnace tools: Furnace
item: (filled) Canned Food
recipe:
input: 4 (Empty) Tin Can, Apple
pattern: .1. .0. ...
group: Functional Blocks group: Functional Blocks
item: Furnace item: Furnace
@@ -240,8 +246,8 @@ describe 'mod_version_parser_v1.coffee', ->
update: Iron Ingot update: Iron Ingot
recipe: recipe:
input: Iron Dust, furnace fuel input: furnace fuel, Iron Dust
pattern: .0. ... .1. pattern: .1. ... .0.
tools: Furnace tools: Furnace
""" """
+8 -4
View File
@@ -47,7 +47,7 @@ describe 'recipe.coffee', ->
recipe = new Recipe input:input, pattern:pattern, output:[new Stack itemSlug:ItemSlug.slugify('gold_gear')] recipe = new Recipe input:input, pattern:pattern, output:[new Stack itemSlug:ItemSlug.slugify('gold_gear')]
recipe.itemSlug.qualified.should.equal 'gold_gear' recipe.itemSlug.qualified.should.equal 'gold_gear'
describe 'getItemSlugAt', -> describe 'getStackAtSlot', ->
beforeEach -> beforeEach ->
input = [ input = [
@@ -57,13 +57,17 @@ describe 'recipe.coffee', ->
recipe = new Recipe itemSlug:'gold_gear', input:input, pattern:'.1. 101 .1.' recipe = new Recipe itemSlug:'gold_gear', input:input, pattern:'.1. 101 .1.'
it 'returns the proper item for an early slot', -> it 'returns the proper item for an early slot', ->
recipe.getItemSlugAt(1).qualified.should.equal 'gold_ingot' stack = recipe.getStackAtSlot(1)
stack.itemSlug.qualified.should.equal 'gold_ingot'
stack.quantity.should.equal 4
it 'returns the proper item for a late slot', -> it 'returns the proper item for a late slot', ->
recipe.getItemSlugAt(4).qualified.should.equal 'iron_gear' stack = recipe.getStackAtSlot(4)
stack.itemSlug.qualified.should.equal 'iron_gear'
stack.quantity.should.equal 1
it 'returns null for an invalid slot', -> it 'returns null for an invalid slot', ->
expect(recipe.getItemSlugAt(12)).to.be.null expect(recipe.getStackAtSlot(12)).to.be.null
describe '_parsePattern', -> describe '_parsePattern', ->