Don't automatically recalculate crafting plans

Instead, any time a change is made which invalidates a crafting plan,
update the visual display to show that the plan is out of date, and
add some extra affordances to recalculate.
This commit is contained in:
Andrew Miner
2016-04-23 11:46:35 -07:00
parent f9b65dd892
commit 962165dc8e
14 changed files with 541 additions and 57 deletions
@@ -27,7 +27,7 @@ module.exports = class CraftingStep
addToolsTo: (targetInventory)->
for stack in @_recipe.tools
targetInventory.add stack.itemSlug, stack.quantity
targetInventory.add stack.itemSlug, stack.quantity, insert:true
completeInto: (targetInventory)->
for stack in @_recipe.output
+20 -14
View File
@@ -22,32 +22,30 @@ module.exports = class Craftsman extends BaseModel
@::PLAN_STEP_INCREMENT = 39
@::STAGE =
WAITING: 'waiting'
EMPTY: 'empty'
READY: 'ready'
GRAPHING: 'examining recipes'
PLANNING: 'computing plans'
ANALYZING: 'analyzing plans'
COMPLETE: 'complete'
INVALID: 'invalid'
OUTDATED: 'outdated'
constructor: (modPack)->
if not modPack? then throw new Error 'modPack is required'
attributes =
paused: false
stage: @STAGE.WAITING
stage: @STAGE.READY
stageCount: 0
super attributes, {}
@_modPack = modPack
reset = _.debounce (=> @reset()), 100
@_have = new Inventory modPack:@_modPack
@_have.on c.event.change, reset
@_have.on c.event.change, => @_resetStage()
@_want = new Inventory modPack:@_modPack
@_want.on c.event.change, reset
@_want.on c.event.change, => @_resetStage()
@on c.event.change + ':paused', reset
@on c.event.change + ':stage', => logger.info "Craftsman has started #{@stage}..."
@on 'scheduleNextWork', => @_scheduleNextWork()
@reset()
@@ -60,10 +58,7 @@ module.exports = class Craftsman extends BaseModel
@_planEvaluator = null
@_plans = null
@stage = @STAGE.WAITING
@stageCount = 0
@_scheduleNextWork()
@_resetStage()
work: ->
return if @_want.isEmpty
@@ -121,7 +116,7 @@ module.exports = class Craftsman extends BaseModel
Object.defineProperties @prototype,
complete:
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID]
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID, @STAGE.OUTDATED]
have:
get: -> @_have
@@ -134,8 +129,19 @@ module.exports = class Craftsman extends BaseModel
# Private Methods ##############################################################################
_resetStage: ->
@stageCount = 0
if @want.isEmpty
if @stage isnt @STAGE.EMPTY
@stage = @STAGE.EMPTY
@reset()
else if not @_plans?
@stage = @STAGE.READY
else
@stage = @STAGE.OUTDATED
_scheduleNextWork: ->
return if @paused
return if @want.isEmpty
return if @complete
+8 -4
View File
@@ -29,10 +29,10 @@ module.exports = class Inventory extends BaseModel
# Public Methods ###############################################################################
add: (itemSlug, quantity=1)->
add: (itemSlug, quantity=1, options={})->
return this unless quantity > 0
@_add itemSlug, quantity
@_add itemSlug, quantity, options
@trigger c.event.add, this, itemSlug, quantity
@trigger c.event.change, this
return this
@@ -209,7 +209,8 @@ module.exports = class Inventory extends BaseModel
# Private Methods ##############################################################################
_add: (itemSlug, quantity=1)->
_add: (itemSlug, quantity=1, options={})->
options.insert ?= false
return unless itemSlug?
return unless quantity > 0
@@ -218,7 +219,10 @@ module.exports = class Inventory extends BaseModel
stack = new Stack itemSlug:itemSlug, quantity:quantity
@listenTo stack, c.event.change, => @trigger c.event.change, this
@_stacks[itemSlug] = stack
@_itemSlugs.push itemSlug
if options.insert
@_itemSlugs.unshift itemSlug
else
@_itemSlugs.push itemSlug
@_sort()
else
stack.quantity += quantity
+1
View File
@@ -40,6 +40,7 @@ module.exports = class CraftPage extends BaseModel
inventory.each (stack)=>
item = @modPack.findItem stack.itemSlug, enableAsNeeded:true
return unless item? and item.isCraftable
@craftsman.want.add stack.itemSlug, stack.quantity
inventory.remove stack.itemSlug
+3 -3
View File
@@ -51,8 +51,6 @@
.panel
.view__inventory.large.editable
section.view__craftsman_working
section.need
h2 Need to Gather
.panel
@@ -60,4 +58,6 @@
section.steps
h2 Steps
.panel
.panel
section.view__craftsman_working
@@ -49,4 +49,14 @@
}
}
}
&.outdated {
section.need .panel {
background: $color-white url('/images/panel-background-outdated.png') repeat;
}
section.steps .panel {
background: $color-white url('/images/panel-background-outdated.png') repeat;
}
}
}
@@ -97,6 +97,7 @@ module.exports = class CraftPageController extends PageController
@_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working',
model: @model.craftsman
@_workingSectionController.on c.event.click, -> window.scrollTo 0, 0
@$haveSection = @$('section.have')
@$instructionsSection = @$('section.instructions')
@@ -117,6 +118,7 @@ module.exports = class CraftPageController extends PageController
refresh: ->
@_needInventoryController.model = @model.craftsman.plan?.need
@_refreshOutdated()
@_refreshSectionVisibility()
@_refreshSteps()
@_adsenseController.fillAdPositions()
@@ -134,7 +136,7 @@ module.exports = class CraftPageController extends PageController
controller.model.addToolsTo @model.craftsman.want
_completeStep: (controller)->
controller.model.completeInto @model.craftsman.have
controller.markComplete @model.craftsman.have
_isAddingToolsPossible: (controller)->
tools = controller.model.recipe.tools
@@ -156,6 +158,12 @@ module.exports = class CraftPageController extends PageController
return true
_refreshOutdated: ->
if @model.craftsman.stage is Craftsman::STAGE.OUTDATED
@$el.addClass 'outdated'
else
@$el.removeClass 'outdated'
_refreshSectionVisibility: ->
return unless @_rendered
@@ -168,11 +176,13 @@ module.exports = class CraftPageController extends PageController
if @model.craftsman.want.isEmpty
visibleSections.push el for el in [@$instructionsSection, @$wantSection]
else if @model.craftsman.stage is Craftsman::STAGE.INVALID
visibleSections.push el for el in [@$wantSection, @$workingSection]
visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection]
else if not @model.craftsman.complete
visibleSections.push el for el in [@$wantSection, @$workingSection]
visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection]
else
visibleSections.push el for el in [@$haveSection, @$needSection, @$stepsSection, @$wantSection]
visibleSections.push el for el in [@$haveSection, @$wantSection, @$workingSection]
if @model.craftsman.plan?
visibleSections.push el for el in [@$needSection, @$stepsSection]
@hide $el for $el in allSections
@show $el for $el in visibleSections
@@ -5,11 +5,16 @@
//- All rights reserved.
//-
.view__item_group.section
.content
.view__craftsman_working
.panel
.waiting
img(src='/images/wait.gif')
.message
p
.count
p
.button: .bezel: p Calculate
.outdated
.message Crafting plan is out of date!
.button: .bezel: p Recalculate
@@ -6,10 +6,7 @@ All rights reserved.
*/
.view__craftsman_working {
.content {
background: $color-white;
box-shadow: none;
.panel {
align-items : center;
display : flex;
flex-direction : column;
@@ -34,5 +31,39 @@ All rights reserved.
font-size: $font-size-medium;
}
}
.button {
margin-top: $size-margin-large;
height: $size-minecraft-block * 2;
width: 50%;
p {
font-size: $font-size-xxlarge;
transform: translateY(-25%);
}
}
}
.outdated {
position: fixed; top: 0; left: 0; right: 0;
background: fade-out($color-white, 0.15) url('/images/panel-background-outdated.png');
border-bottom: $size-border-medium solid $color-black;
display: flex;
flex-direction: column;
align-items: center;
.message {
margin-top: $size-margin-medium;
font-family: $font-family-header;
font-size: $font-size-xlarge;
}
.button {
width: $size-minecraft-block * 10;
margin: $size-margin-medium;
}
}
}
@@ -12,48 +12,94 @@ Craftsman = require '../../../models/crafting/craftsman'
module.exports = class CraftsmanWorkingController extends BaseController
@::HIDE_TIMER_DURATION = 2000
constructor: (options={})->
if not options.model then throw new Error 'options.model is required'
options.templateName = 'craft_page/craftsman_working'
super options
@model.on c.event.change, => @_refreshStatusText()
@_hideTimer = null
# Event Methods ################################################################################
onButtonClicked: ->
@trigger c.event.click
@model.reset()
@model.work()
return false
# BaseController Methods #######################################################################
onDidModelChange: ->
@refresh()
onDidRender: ->
@$message = @$('.message p')
@$count = @$('.count p')
@$waiting = @$('.waiting')
@$button = @$('.button')
@$count = @$('.count p')
@$message = @$('.message p')
@$outdated = @$('.outdated')
@$waiting = @$('.waiting')
@_controls = [@$button, @$count, @$message, @$outdated, @$waiting]
super
refresh: ->
@_refreshStatusText()
super
# Private Methods ##############################################################################
_refreshStatusText: ->
return unless @$message? and @$count?
@show @$waiting
button = count = message = outdated = waiting = null
switch @model.stage
when Craftsman::STAGE.WAITING
@$message.html 'Preparing crafting calculation...'
@$count.html ''
when Craftsman::STAGE.READY
message = 'Ready to compute crafting plan!'
count = 'Click "Calculate" to continue.'
button = true
when Craftsman::STAGE.GRAPHING
@$message.html 'Researching recipes...'
@$count.html "Found #{@model.stageCount} recipes so far..."
message = 'Researching recipes...'
count = "Found #{@model.stageCount} recipes so far..."
watiing = true
when Craftsman::STAGE.PLANNING
@$message.html 'Figuring out possible crafting plans...'
@$count.html "Found #{@model.stageCount} possibilities so far..."
message = 'Figuring out possible crafting plans...'
count = "Found #{@model.stageCount} possibilities so far..."
watiing = true
when Craftsman::STAGE.ANALYZING
@$message.html 'Looking for the best plan...'
@$count.html "Finished checking #{@model.stageCount} so far..."
message = 'Looking for the best plan...'
count = "Finished checking #{@model.stageCount} so far..."
watiing = true
when Craftsman::STAGE.COMPLETE
@$message.html 'All done!'
@$count.html ''
message = 'Crafting plan is complete.'
when Craftsman::STAGE.INVALID
@$message.html 'Couldn\'t make a crafting plan'
@$count.html ''
@hide @waiting
message = 'Couldn\'t make a crafting plan!'
count = 'Please report this problem using the Feedback box.'
when Craftsman::STAGE.OUTDATED
message = 'Your crafting plan is out of date!'
count = 'Click "Calculate" to re-compute.'
button = true
outdated = true
@hide(control) for control in @_controls
if button?
@show @$button
if count?
@show @$count
@$count.html count
if message?
@show @$message
@$message.html message
if waiting?
@show @$waiting
if outdated?
@show @$outdated
super
# Backbone.View Overrides ######################################################################
events: ->
return _.extend super,
'click .button': 'onButtonClicked'
@@ -53,4 +53,12 @@
}
}
}
&.complete {
opacity: 0.25;
h3 {
text-decoration: line-through;
}
}
}
@@ -29,6 +29,13 @@ module.exports = class StepController extends BaseController
@onComplete = options.onComplete or (controller)-> # do nothing
@onAddTools = options.onAddTools or (controller)-> # do nothing
# Public Methods ###############################################################################
markComplete: (targetInventory)->
@$el.addClass 'complete'
@$completeButton.addClass 'disabled'
@model.completeInto targetInventory
# Event Methods ################################################################################
onCompleteButtonClicked: (event)->
@@ -63,6 +70,9 @@ module.exports = class StepController extends BaseController
onWillChangeModel: (oldModel, newModel)->
if not newModel? then throw new Error 'model cannot be null'
if @rendered
@$el.removeClass 'complete'
@$completeButton.removeClass 'disabled'
return super
refresh: ->