* Remove V1 of the mod version parser and shift V2 up to be V1 * Add a parser for mod.cg files, and refactor the the mod-version.cg files to push the appropriate content up to the mod.cg * Remove the concept of "silent" from BaseModel along with logging each event as they are fired (which is what really prompted the need for it in the first place) * Move use of the Storage class to be completely the province of the controllers most closely related to models affected * Convert the ModVersionController to the ModController and have it take on responsibility for choosing the mod version * Update BaseModel to support simple accessors for the current state * Update CraftingPlan to be able to remove uncraftable items * Implement the Mod model
155 lines
4.5 KiB
CoffeeScript
155 lines
4.5 KiB
CoffeeScript
###
|
|
Crafting Guide - crafting_plan.coffee
|
|
|
|
Copyright (c) 2014-2015 by Redwood Labs
|
|
All rights reserved.
|
|
###
|
|
|
|
BaseModel = require './base_model'
|
|
{Event} = require '../constants'
|
|
Inventory = require './inventory'
|
|
|
|
########################################################################################################################
|
|
|
|
module.exports = class CraftingPlan extends BaseModel
|
|
|
|
constructor: (attributes={}, options={})->
|
|
if not attributes.modPack then throw new Error 'modPack is required'
|
|
attributes.includingTools ?= false
|
|
super attributes, options
|
|
|
|
@have = new Inventory
|
|
@want = new Inventory
|
|
@need = new Inventory
|
|
@result = new Inventory
|
|
|
|
@clear()
|
|
|
|
@have.on Event.change, => @craft()
|
|
@want.on Event.change, => @craft()
|
|
@modPack.on Event.change, => @craft()
|
|
|
|
@on Event.change + ':includingTools', => @craft()
|
|
|
|
# Public Methods ###############################################################################
|
|
|
|
clear: (options={})->
|
|
@steps = []
|
|
@need.clear()
|
|
@result.clear()
|
|
|
|
@trigger 'change', this
|
|
return this
|
|
|
|
craft: ->
|
|
@clear()
|
|
|
|
@result.addInventory @have
|
|
|
|
@steps = {}
|
|
@want.each (stack)=>
|
|
@_findSteps stack.slug
|
|
@need.add stack.slug, stack.quantity
|
|
|
|
@steps = _.values @steps
|
|
@_resolveNeeds()
|
|
@_removeExtraSteps()
|
|
@result.addInventory @want
|
|
|
|
@need.trigger 'change', @need
|
|
@result.trigger 'change', @result
|
|
@trigger 'change', this
|
|
|
|
removeUncraftableItems: ->
|
|
toRemove = []
|
|
@want.each (stack)=>
|
|
item = @modPack.findItem stack.slug
|
|
if not item? then toRemove.push stack.slug
|
|
|
|
for slug in toRemove
|
|
@want.remove slug
|
|
|
|
# Event Methods ################################################################################
|
|
|
|
onIncludingToolsChanged: ->
|
|
@storage.setItem 'includingTools', "#{@includingTools}"
|
|
@craft()
|
|
|
|
# Object Overrides #############################################################################
|
|
|
|
toString: ->
|
|
return "#{@constructor.name} {
|
|
have:#{@have},
|
|
want:#{@want},
|
|
need:#{@_need},
|
|
result:#{@result},
|
|
steps:#{@steps}
|
|
}"
|
|
|
|
# Private Methods ##############################################################################
|
|
|
|
_addStep: (recipe)->
|
|
return if @_hasStep recipe.slug
|
|
logger.verbose "adding step: #{recipe.slug}"
|
|
@steps[recipe.slug] = recipe:recipe
|
|
|
|
_chooseRecipe: (item)->
|
|
return item.getPrimaryRecipe()
|
|
|
|
_findSteps: (slug)->
|
|
item = @modPack.findItem slug
|
|
return unless item?
|
|
return unless item.isCraftable
|
|
return if item.isGatherable
|
|
|
|
recipe = @_chooseRecipe item
|
|
|
|
if @includingTools
|
|
for toolStack in recipe.tools
|
|
if not @_hasStep toolStack.slug
|
|
@_findSteps toolStack.slug
|
|
|
|
for inputStack in recipe.input
|
|
@_findSteps inputStack.slug
|
|
|
|
@_addStep recipe
|
|
|
|
_hasStep: (slug)->
|
|
return @steps[slug]?
|
|
|
|
_removeExtraSteps: ->
|
|
result = (step for step in @steps when step.multiplier > 0)
|
|
@steps = result
|
|
|
|
_resolveNeeds: ->
|
|
for i in [@steps.length-1..0] by -1
|
|
step = @steps[i]
|
|
recipe = step.recipe
|
|
|
|
step.multiplier = Math.ceil(@need.quantityOf(recipe.slug) / step.recipe.output[0].quantity)
|
|
|
|
if @includingTools
|
|
for stack in recipe.tools
|
|
slug = stack.slug
|
|
available = @result.quantityOf(slug) + @need.quantityOf(slug)
|
|
needed = Math.max 0, stack.quantity - available
|
|
|
|
@need.add stack.slug, needed
|
|
@result.add stack.slug, needed
|
|
|
|
for stack in recipe.input
|
|
needed = step.multiplier * stack.quantity
|
|
consumed = Math.min needed, @result.quantityOf(stack.slug)
|
|
remaining = needed - consumed
|
|
|
|
@result.remove stack.slug, consumed
|
|
@need.add stack.slug, remaining
|
|
|
|
for stack in recipe.output
|
|
created = stack.quantity * step.multiplier
|
|
consumed = Math.min created, @need.quantityOf stack.slug
|
|
remaining = created - consumed
|
|
|
|
@result.add stack.slug, remaining
|
|
@need.remove stack.slug, consumed
|