253 lines
8.1 KiB
CoffeeScript
253 lines
8.1 KiB
CoffeeScript
#
|
|
# Crafting Guide - recipe.coffee
|
|
#
|
|
# Copyright © 2014-2016 by Redwood Labs
|
|
# All rights reserved.
|
|
#
|
|
|
|
BaseModel = require '../base_model'
|
|
ItemSlug = require './item_slug'
|
|
Stack = require './stack'
|
|
{StringBuilder} = require 'crafting-guide-common'
|
|
|
|
########################################################################################################################
|
|
|
|
module.exports = class Recipe extends BaseModel
|
|
|
|
constructor: (attributes={}, options={})->
|
|
if not attributes.input? then throw new Error 'attributes.input is required'
|
|
if not attributes.pattern? then throw new Error 'attributes.pattern is required'
|
|
|
|
if attributes.itemSlug? and not attributes.output?
|
|
attributes.output = [new Stack itemSlug:attributes.itemSlug, quantity:1]
|
|
else if attributes.output? and not attributes.itemSlug?
|
|
if attributes.output.length is 0 then throw new Error 'attributes.output cannot be empty'
|
|
attributes.itemSlug = attributes.output[0].itemSlug
|
|
else
|
|
throw new Error 'attributes.itemSlug or attributes.output is required'
|
|
|
|
attributes.pattern = @_parsePattern attributes.pattern
|
|
|
|
attributes.condition ?= null
|
|
attributes.ignoreDuringCrafting ?= false
|
|
attributes.modVersion ?= null
|
|
attributes.tools ?= []
|
|
options.logEvents ?= false
|
|
super attributes, options
|
|
|
|
@_computeQuantities attributes.pattern
|
|
|
|
@on c.event.change + ':modVersion', => @_slug = null
|
|
@on c.event.change + ':pattern', => @_patternCache = null
|
|
|
|
# Class Methods ################################################################################
|
|
|
|
@compareFor: (a, b, itemSlug)->
|
|
if itemSlug?
|
|
aValue = a.itemSlug.matches itemSlug
|
|
bValue = b.itemSlug.matches itemSlug
|
|
if aValue isnt bValue
|
|
return -1 if aValue
|
|
return +1 if bValue
|
|
|
|
aValue = a.getQuantityProduced itemSlug
|
|
bValue = b.getQuantityProduced itemSlug
|
|
if aValue isnt bValue
|
|
return if aValue > bValue then -1 else +1
|
|
|
|
return 0
|
|
|
|
# Public Methods ###############################################################################
|
|
|
|
getStackAtSlot: (patternSlot)->
|
|
trueIndex = 0:0, 1:1, 2:2, 3:4, 4:5, 5:6, 6:8, 7:9, 8:10
|
|
patternDigit = @pattern[trueIndex[patternSlot]]
|
|
return null unless patternDigit?
|
|
return null unless patternDigit.match /[0-9]/
|
|
|
|
stack = @input[parseInt(patternDigit)]
|
|
return null unless stack?
|
|
|
|
return stack
|
|
|
|
getQuantityProduced: (itemSlug)->
|
|
total = 0
|
|
for stack in @output
|
|
if stack.itemSlug.matches itemSlug
|
|
total += stack.quantity
|
|
|
|
return total
|
|
|
|
getQuantityRequired: (itemSlug)->
|
|
total = 0
|
|
for stack, index in @input
|
|
if ItemSlug.equal stack.itemSlug, itemSlug
|
|
total += @_quantities[index] * stack.quantity
|
|
|
|
return total
|
|
|
|
hasAllTools: (modPack)->
|
|
modPack ?= @modVersion?.mod?.modPack
|
|
return true unless modPack?
|
|
|
|
for stack in @tools
|
|
return false unless modPack.findItem stack.itemSlug
|
|
return true
|
|
|
|
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
|
|
if stack.itemSlug.matches itemSlug
|
|
amountCreated += stack.quantity
|
|
|
|
for stack in @input
|
|
if stack.itemSlug.matches itemSlug
|
|
amountCreated -= stack.quantity
|
|
|
|
return amountCreated <= 0
|
|
|
|
produces: (itemSlug)->
|
|
if not @_produces?
|
|
@_produces = {}
|
|
|
|
for stack in @output
|
|
actuallyProduces = not @isPassThroughFor stack.itemSlug
|
|
@_produces[stack.itemSlug.qualified] = actuallyProduces
|
|
|
|
result = @_produces[itemSlug.qualified] or @_produces[itemSlug.item]
|
|
return result
|
|
|
|
requires: (itemSlug)->
|
|
for stack in @input
|
|
if stack.itemSlug.matches itemSlug
|
|
return true
|
|
return false
|
|
|
|
requiresTool: (itemSlug)->
|
|
for stack in @tools
|
|
if stack.itemSlug.matches itemSlug
|
|
return true
|
|
|
|
# Property Methods #############################################################################
|
|
|
|
Object.defineProperties @prototype,
|
|
|
|
slug:
|
|
get: ->
|
|
if not @_slug?
|
|
builder = new StringBuilder
|
|
delimiterNeeded = false
|
|
for stack in @input
|
|
if delimiterNeeded then builder.push ','
|
|
delimiterNeeded = true
|
|
|
|
if stack.quantity > 1 then builder.push stack.quantity, ' '
|
|
builder.push stack.itemSlug.qualified
|
|
|
|
builder.push '>'
|
|
builder.push @pattern
|
|
builder.push '>'
|
|
for stack in @tools
|
|
builder.push stack.itemSlug.qualified
|
|
builder.push '>'
|
|
|
|
delimiterNeeded = false
|
|
for stack in @output
|
|
if delimiterNeeded then builder.push ','
|
|
delimiterNeeded = true
|
|
|
|
if stack.quantity > 1 then builder.push stack.quantity, ' '
|
|
builder.push stack.itemSlug.qualified
|
|
|
|
@_slug = builder.toString()
|
|
|
|
return @_slug
|
|
|
|
# Object Overrides #############################################################################
|
|
|
|
toString: ->
|
|
result = [@constructor.name, " (", @cid, ") { name:", @name]
|
|
|
|
result.push ", input:["
|
|
needsDelimiter = false
|
|
for stack in @input
|
|
if needsDelimiter then result.push ', '
|
|
result.push @getQuantityRequired stack.itemSlug
|
|
result.push ' '
|
|
result.push stack.itemSlug
|
|
needsDelimiter = true
|
|
result.push ']'
|
|
|
|
result.push ", output:["
|
|
needsDelimiter = false
|
|
for stack in @output
|
|
if needsDelimiter then result.push ', '
|
|
result.push @getQuantityProduced stack.itemSlug
|
|
result.push ' '
|
|
result.push stack.itemSlug
|
|
needsDelimiter = true
|
|
result.push ']'
|
|
|
|
if @tools.length > 0
|
|
result.push ", tools:["
|
|
needsDelimiter = false
|
|
for stack in @tools
|
|
if needsDelimiter then result.push ', '
|
|
result.push stack.toString()
|
|
needsDelimiter = true
|
|
result.push ']'
|
|
|
|
result.push '}'
|
|
return result.join ''
|
|
|
|
# Private Methods ##############################################################################
|
|
|
|
_computeQuantities: (pattern)->
|
|
quantityMap = {}
|
|
|
|
for c in pattern.split ''
|
|
continue if c is '.'
|
|
continue if c is ' '
|
|
|
|
if quantityMap[c]?
|
|
quantityMap[c] += 1
|
|
else
|
|
quantityMap[c] = 1
|
|
|
|
@_quantities = []
|
|
for i in [0...@input.length]
|
|
@_quantities.push quantityMap["#{i}"]
|
|
|
|
_parsePattern: (pattern)->
|
|
return unless pattern?
|
|
|
|
pattern = pattern.replace /\ /g, ''
|
|
return if pattern.length is 0
|
|
|
|
pattern = pattern.replace /[^0-9]/g, '.'
|
|
|
|
array = pattern.split ''
|
|
array = array[0...9]
|
|
while array.length isnt 9
|
|
array.push '.'
|
|
|
|
pattern = array.join ''
|
|
pattern = pattern.replace /(...)(...)(...)/, '$1 $2 $3'
|
|
return pattern
|