128 lines
3.7 KiB
CoffeeScript
128 lines
3.7 KiB
CoffeeScript
#
|
|
# Crafting Guide - plan_builder.coffee
|
|
#
|
|
# Copyright © 2014-2016 by Redwood Labs
|
|
# All rights reserved.
|
|
#
|
|
|
|
CraftingNode = require './crafting_node'
|
|
CraftingPlan = require './crafting_plan'
|
|
CraftingStep = require './crafting_step'
|
|
Inventory = require '../game/inventory'
|
|
|
|
########################################################################################################################
|
|
|
|
module.exports = class PlanBuilder
|
|
|
|
constructor: (rootNode, modPack, options={})->
|
|
if not rootNode? then throw new Error 'rootNode is required'
|
|
if not modPack? then throw new Error 'modPack is required'
|
|
|
|
@want = options.want
|
|
@have = options.have
|
|
|
|
@_choiceNodes = []
|
|
@_complete = false
|
|
@_maxPlanCount = c.limits.maximumPlanCount
|
|
@_modPack = modPack
|
|
@_plans = []
|
|
@_rootNode = rootNode
|
|
|
|
@_isolateChoiceNodes()
|
|
|
|
# Public Methods ###############################################################################
|
|
|
|
producePlans: (maxPlans=null)->
|
|
maxPlans = if maxPlans then @plans.length + maxPlans else Number.MAX_VALUE
|
|
|
|
if @plans.length >= @_maxPlanCount
|
|
@_complete = true
|
|
|
|
while not @complete and (@plans.length < maxPlans)
|
|
plan = @_captureCurrentPlan()
|
|
if plan?
|
|
@plans.push plan
|
|
|
|
@_incrementChoiceNodes()
|
|
|
|
return @_plans
|
|
|
|
# Property Methods #############################################################################
|
|
|
|
Object.defineProperties @prototype,
|
|
|
|
complete:
|
|
get: -> @_complete
|
|
|
|
have:
|
|
get: -> @_have
|
|
set: (have)-> @_have = have or new Inventory
|
|
|
|
maxPlanCount:
|
|
get: -> @_maxPlanCount
|
|
set: (value)-> @_maxPlanCount = value
|
|
|
|
plans:
|
|
get: -> @_plans
|
|
|
|
want:
|
|
get: -> @_want
|
|
set: (want)-> @_want = want or new Inventory
|
|
|
|
# Private Methods ##############################################################################
|
|
|
|
_captureCurrentPlan: ->
|
|
toVisit = [@_rootNode]
|
|
stepNodes = []
|
|
|
|
while toVisit.length > 0
|
|
node = toVisit.shift()
|
|
|
|
if node.TYPE is CraftingNode::TYPES.INVENTORY
|
|
toVisit.push(c) for c in node.children
|
|
else if node.TYPE is CraftingNode::TYPES.ITEM
|
|
toVisit.push node.children[0] if node.children.length > 0
|
|
else if node.TYPE is CraftingNode::TYPES.RECIPE
|
|
stepNodes.push node
|
|
toVisit.push(c) for c in node.children
|
|
|
|
steps = []
|
|
seenRecipes = {}
|
|
index = stepNodes.length - 1
|
|
while index >= 0
|
|
node = stepNodes[index]
|
|
index -= 1
|
|
return null unless node.valid and node.complete
|
|
|
|
recipeSlug = node.recipe.slug
|
|
continue if seenRecipes[recipeSlug]?
|
|
|
|
seenRecipes[recipeSlug] = true
|
|
steps.push new CraftingStep node.recipe, @_modPack
|
|
|
|
plan = new CraftingPlan @_modPack, @_want, @_have, steps
|
|
return plan
|
|
|
|
_incrementChoiceNodes: ->
|
|
if @_choiceNodes.length is 0
|
|
@_complete = true
|
|
return
|
|
|
|
index = @_choiceNodes.length - 1
|
|
while true
|
|
if index is -1
|
|
@_complete = true
|
|
return
|
|
|
|
node = @_choiceNodes[index]
|
|
node.rotateChildren()
|
|
|
|
return unless node.rotations % node.children.length is 0
|
|
index -= 1
|
|
|
|
_isolateChoiceNodes: ->
|
|
@_rootNode.acceptVisitor
|
|
onEnterItemNode: (node)=>
|
|
if node.children.length > 1
|
|
@_choiceNodes.push node
|