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
Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

@@ -0,0 +1,353 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ActiveLayerIndex</key>
<integer>0</integer>
<key>ApplicationVersion</key>
<array>
<string>com.omnigroup.OmniGraffle.MacAppStore</string>
<string>139.18</string>
</array>
<key>AutoAdjust</key>
<false/>
<key>BackgroundGraphic</key>
<dict>
<key>Bounds</key>
<string>{{0, 0}, {320, 320}}</string>
<key>Class</key>
<string>SolidGraphic</string>
<key>ID</key>
<integer>2</integer>
<key>Style</key>
<dict>
<key>shadow</key>
<dict>
<key>Draws</key>
<string>NO</string>
</dict>
<key>stroke</key>
<dict>
<key>Draws</key>
<string>NO</string>
</dict>
</dict>
</dict>
<key>BaseZoom</key>
<integer>0</integer>
<key>CanvasOrigin</key>
<string>{0, 0}</string>
<key>CanvasSize</key>
<string>{320, 320}</string>
<key>ColumnAlign</key>
<integer>1</integer>
<key>ColumnSpacing</key>
<real>36</real>
<key>CreationDate</key>
<string>2016-04-23 05:39:56 +0000</string>
<key>Creator</key>
<string>Andrew Miner</string>
<key>DisplayScale</key>
<string>1 pt = 1 px</string>
<key>GraphDocumentVersion</key>
<integer>8</integer>
<key>GraphicsList</key>
<array>
<dict>
<key>AllowConnections</key>
<string>NO</string>
<key>AllowLabelDrop</key>
<false/>
<key>AllowToConnect</key>
<false/>
<key>Class</key>
<string>LineGraphic</string>
<key>ID</key>
<integer>5</integer>
<key>Points</key>
<array>
<string>{160, 480}</string>
<string>{480, 160}</string>
</array>
<key>Style</key>
<dict>
<key>stroke</key>
<dict>
<key>Cap</key>
<integer>0</integer>
<key>Color</key>
<dict>
<key>a</key>
<string>0.1</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>HeadArrow</key>
<string>0</string>
<key>Legacy</key>
<true/>
<key>TailArrow</key>
<string>0</string>
<key>Width</key>
<real>120</real>
</dict>
</dict>
</dict>
<dict>
<key>AllowConnections</key>
<string>NO</string>
<key>AllowLabelDrop</key>
<false/>
<key>AllowToConnect</key>
<false/>
<key>Class</key>
<string>LineGraphic</string>
<key>ID</key>
<integer>4</integer>
<key>Points</key>
<array>
<string>{-160, 160}</string>
<string>{160, -160}</string>
</array>
<key>Style</key>
<dict>
<key>stroke</key>
<dict>
<key>Cap</key>
<integer>0</integer>
<key>Color</key>
<dict>
<key>a</key>
<string>0.1</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>HeadArrow</key>
<string>0</string>
<key>Legacy</key>
<true/>
<key>TailArrow</key>
<string>0</string>
<key>Width</key>
<real>120</real>
</dict>
</dict>
</dict>
<dict>
<key>AllowConnections</key>
<string>NO</string>
<key>AllowLabelDrop</key>
<false/>
<key>AllowToConnect</key>
<false/>
<key>Class</key>
<string>LineGraphic</string>
<key>ID</key>
<integer>3</integer>
<key>Points</key>
<array>
<string>{0, 320}</string>
<string>{320, 0}</string>
</array>
<key>Style</key>
<dict>
<key>stroke</key>
<dict>
<key>Cap</key>
<integer>0</integer>
<key>Color</key>
<dict>
<key>a</key>
<string>0.1</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>HeadArrow</key>
<string>0</string>
<key>Legacy</key>
<true/>
<key>TailArrow</key>
<string>0</string>
<key>Width</key>
<real>120</real>
</dict>
</dict>
</dict>
</array>
<key>GridInfo</key>
<dict>
<key>GridSpacing</key>
<real>10</real>
<key>MajorGridSpacing</key>
<integer>10</integer>
<key>ShowsGrid</key>
<string>YES</string>
<key>SnapsToGrid</key>
<string>YES</string>
</dict>
<key>GuidesLocked</key>
<string>NO</string>
<key>GuidesVisible</key>
<string>YES</string>
<key>HPages</key>
<integer>1</integer>
<key>ImageCounter</key>
<integer>1</integer>
<key>KeepToScale</key>
<false/>
<key>Layers</key>
<array>
<dict>
<key>Lock</key>
<string>NO</string>
<key>Name</key>
<string>Layer 1</string>
<key>Print</key>
<string>YES</string>
<key>View</key>
<string>YES</string>
</dict>
</array>
<key>LayoutInfo</key>
<dict>
<key>Animate</key>
<string>NO</string>
<key>circoMinDist</key>
<real>18</real>
<key>circoSeparation</key>
<real>0.0</real>
<key>layoutEngine</key>
<string>dot</string>
<key>neatoSeparation</key>
<real>0.0</real>
<key>twopiSeparation</key>
<real>0.0</real>
</dict>
<key>LinksVisible</key>
<string>NO</string>
<key>MagnetsVisible</key>
<string>NO</string>
<key>MasterSheets</key>
<array/>
<key>ModificationDate</key>
<string>2016-04-23 05:58:40 +0000</string>
<key>Modifier</key>
<string>Andrew Miner</string>
<key>NotesVisible</key>
<string>NO</string>
<key>Orientation</key>
<integer>2</integer>
<key>OriginVisible</key>
<string>NO</string>
<key>PageBreaks</key>
<string>NO</string>
<key>PrintInfo</key>
<dict>
<key>NSBottomMargin</key>
<array>
<string>float</string>
<string>41</string>
</array>
<key>NSHorizonalPagination</key>
<array>
<string>coded</string>
<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
</array>
<key>NSLeftMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
<key>NSPaperSize</key>
<array>
<string>size</string>
<string>{611.99998474121094, 792}</string>
</array>
<key>NSPrintReverseOrientation</key>
<array>
<string>int</string>
<string>0</string>
</array>
<key>NSRightMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
<key>NSTopMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
</dict>
<key>PrintOnePage</key>
<false/>
<key>ReadOnly</key>
<string>NO</string>
<key>RowAlign</key>
<integer>1</integer>
<key>RowSpacing</key>
<real>36</real>
<key>SheetTitle</key>
<string>Canvas 1</string>
<key>SmartAlignmentGuidesActive</key>
<string>YES</string>
<key>SmartDistanceGuidesActive</key>
<string>YES</string>
<key>UniqueID</key>
<integer>1</integer>
<key>UseEntirePage</key>
<false/>
<key>VPages</key>
<integer>1</integer>
<key>WindowInfo</key>
<dict>
<key>CurrentSheet</key>
<integer>0</integer>
<key>ExpandedCanvases</key>
<array>
<dict>
<key>name</key>
<string>Canvas 1</string>
</dict>
</array>
<key>Frame</key>
<string>{{215, 0}, {2134, 1417}}</string>
<key>ListView</key>
<true/>
<key>OutlineWidth</key>
<integer>142</integer>
<key>RightSidebar</key>
<false/>
<key>ShowRuler</key>
<true/>
<key>Sidebar</key>
<true/>
<key>SidebarWidth</key>
<integer>120</integer>
<key>VisibleRegion</key>
<string>{{-840, -477}, {1999, 1275}}</string>
<key>Zoom</key>
<real>1</real>
<key>ZoomValues</key>
<array>
<array>
<string>Canvas 1</string>
<real>1</real>
<real>1</real>
</array>
</array>
</dict>
</dict>
</plist>
@@ -27,7 +27,7 @@ module.exports = class CraftingStep
addToolsTo: (targetInventory)-> addToolsTo: (targetInventory)->
for stack in @_recipe.tools for stack in @_recipe.tools
targetInventory.add stack.itemSlug, stack.quantity targetInventory.add stack.itemSlug, stack.quantity, insert:true
completeInto: (targetInventory)-> completeInto: (targetInventory)->
for stack in @_recipe.output for stack in @_recipe.output
+20 -14
View File
@@ -22,32 +22,30 @@ module.exports = class Craftsman extends BaseModel
@::PLAN_STEP_INCREMENT = 39 @::PLAN_STEP_INCREMENT = 39
@::STAGE = @::STAGE =
WAITING: 'waiting' EMPTY: 'empty'
READY: 'ready'
GRAPHING: 'examining recipes' GRAPHING: 'examining recipes'
PLANNING: 'computing plans' PLANNING: 'computing plans'
ANALYZING: 'analyzing plans' ANALYZING: 'analyzing plans'
COMPLETE: 'complete' COMPLETE: 'complete'
INVALID: 'invalid' INVALID: 'invalid'
OUTDATED: 'outdated'
constructor: (modPack)-> constructor: (modPack)->
if not modPack? then throw new Error 'modPack is required' if not modPack? then throw new Error 'modPack is required'
attributes = attributes =
paused: false stage: @STAGE.READY
stage: @STAGE.WAITING
stageCount: 0 stageCount: 0
super attributes, {} super attributes, {}
@_modPack = modPack @_modPack = modPack
reset = _.debounce (=> @reset()), 100
@_have = new Inventory modPack:@_modPack @_have = new Inventory modPack:@_modPack
@_have.on c.event.change, reset @_have.on c.event.change, => @_resetStage()
@_want = new Inventory modPack:@_modPack @_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 c.event.change + ':stage', => logger.info "Craftsman has started #{@stage}..."
@on 'scheduleNextWork', => @_scheduleNextWork() @on 'scheduleNextWork', => @_scheduleNextWork()
@reset() @reset()
@@ -60,10 +58,7 @@ module.exports = class Craftsman extends BaseModel
@_planEvaluator = null @_planEvaluator = null
@_plans = null @_plans = null
@stage = @STAGE.WAITING @_resetStage()
@stageCount = 0
@_scheduleNextWork()
work: -> work: ->
return if @_want.isEmpty return if @_want.isEmpty
@@ -121,7 +116,7 @@ module.exports = class Craftsman extends BaseModel
Object.defineProperties @prototype, Object.defineProperties @prototype,
complete: complete:
get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID] get: -> @stage in [@STAGE.COMPLETE, @STAGE.INVALID, @STAGE.OUTDATED]
have: have:
get: -> @_have get: -> @_have
@@ -134,8 +129,19 @@ module.exports = class Craftsman extends BaseModel
# Private Methods ############################################################################## # 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: -> _scheduleNextWork: ->
return if @paused
return if @want.isEmpty return if @want.isEmpty
return if @complete return if @complete
+7 -3
View File
@@ -29,10 +29,10 @@ module.exports = class Inventory extends BaseModel
# Public Methods ############################################################################### # Public Methods ###############################################################################
add: (itemSlug, quantity=1)-> add: (itemSlug, quantity=1, options={})->
return this unless quantity > 0 return this unless quantity > 0
@_add itemSlug, quantity @_add itemSlug, quantity, options
@trigger c.event.add, this, itemSlug, quantity @trigger c.event.add, this, itemSlug, quantity
@trigger c.event.change, this @trigger c.event.change, this
return this return this
@@ -209,7 +209,8 @@ module.exports = class Inventory extends BaseModel
# Private Methods ############################################################################## # Private Methods ##############################################################################
_add: (itemSlug, quantity=1)-> _add: (itemSlug, quantity=1, options={})->
options.insert ?= false
return unless itemSlug? return unless itemSlug?
return unless quantity > 0 return unless quantity > 0
@@ -218,6 +219,9 @@ module.exports = class Inventory extends BaseModel
stack = new Stack itemSlug:itemSlug, quantity:quantity stack = new Stack itemSlug:itemSlug, quantity:quantity
@listenTo stack, c.event.change, => @trigger c.event.change, this @listenTo stack, c.event.change, => @trigger c.event.change, this
@_stacks[itemSlug] = stack @_stacks[itemSlug] = stack
if options.insert
@_itemSlugs.unshift itemSlug
else
@_itemSlugs.push itemSlug @_itemSlugs.push itemSlug
@_sort() @_sort()
else else
+1
View File
@@ -40,6 +40,7 @@ module.exports = class CraftPage extends BaseModel
inventory.each (stack)=> inventory.each (stack)=>
item = @modPack.findItem stack.itemSlug, enableAsNeeded:true item = @modPack.findItem stack.itemSlug, enableAsNeeded:true
return unless item? and item.isCraftable return unless item? and item.isCraftable
@craftsman.want.add stack.itemSlug, stack.quantity @craftsman.want.add stack.itemSlug, stack.quantity
inventory.remove stack.itemSlug inventory.remove stack.itemSlug
+2 -2
View File
@@ -51,8 +51,6 @@
.panel .panel
.view__inventory.large.editable .view__inventory.large.editable
section.view__craftsman_working
section.need section.need
h2 Need to Gather h2 Need to Gather
.panel .panel
@@ -61,3 +59,5 @@
section.steps section.steps
h2 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', @_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working',
model: @model.craftsman model: @model.craftsman
@_workingSectionController.on c.event.click, -> window.scrollTo 0, 0
@$haveSection = @$('section.have') @$haveSection = @$('section.have')
@$instructionsSection = @$('section.instructions') @$instructionsSection = @$('section.instructions')
@@ -117,6 +118,7 @@ module.exports = class CraftPageController extends PageController
refresh: -> refresh: ->
@_needInventoryController.model = @model.craftsman.plan?.need @_needInventoryController.model = @model.craftsman.plan?.need
@_refreshOutdated()
@_refreshSectionVisibility() @_refreshSectionVisibility()
@_refreshSteps() @_refreshSteps()
@_adsenseController.fillAdPositions() @_adsenseController.fillAdPositions()
@@ -134,7 +136,7 @@ module.exports = class CraftPageController extends PageController
controller.model.addToolsTo @model.craftsman.want controller.model.addToolsTo @model.craftsman.want
_completeStep: (controller)-> _completeStep: (controller)->
controller.model.completeInto @model.craftsman.have controller.markComplete @model.craftsman.have
_isAddingToolsPossible: (controller)-> _isAddingToolsPossible: (controller)->
tools = controller.model.recipe.tools tools = controller.model.recipe.tools
@@ -156,6 +158,12 @@ module.exports = class CraftPageController extends PageController
return true return true
_refreshOutdated: ->
if @model.craftsman.stage is Craftsman::STAGE.OUTDATED
@$el.addClass 'outdated'
else
@$el.removeClass 'outdated'
_refreshSectionVisibility: -> _refreshSectionVisibility: ->
return unless @_rendered return unless @_rendered
@@ -168,11 +176,13 @@ module.exports = class CraftPageController extends PageController
if @model.craftsman.want.isEmpty if @model.craftsman.want.isEmpty
visibleSections.push el for el in [@$instructionsSection, @$wantSection] visibleSections.push el for el in [@$instructionsSection, @$wantSection]
else if @model.craftsman.stage is Craftsman::STAGE.INVALID 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 else if not @model.craftsman.complete
visibleSections.push el for el in [@$wantSection, @$workingSection] visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection]
else 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 @hide $el for $el in allSections
@show $el for $el in visibleSections @show $el for $el in visibleSections
@@ -5,11 +5,16 @@
//- All rights reserved. //- All rights reserved.
//- //-
.view__item_group.section .view__craftsman_working
.content .panel
.waiting .waiting
img(src='/images/wait.gif') img(src='/images/wait.gif')
.message .message
p p
.count .count
p 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 { .view__craftsman_working {
.content { .panel {
background: $color-white;
box-shadow: none;
align-items : center; align-items : center;
display : flex; display : flex;
flex-direction : column; flex-direction : column;
@@ -34,5 +31,39 @@ All rights reserved.
font-size: $font-size-medium; 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 module.exports = class CraftsmanWorkingController extends BaseController
@::HIDE_TIMER_DURATION = 2000
constructor: (options={})-> constructor: (options={})->
if not options.model then throw new Error 'options.model is required' if not options.model then throw new Error 'options.model is required'
options.templateName = 'craft_page/craftsman_working' options.templateName = 'craft_page/craftsman_working'
super options 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 ####################################################################### # BaseController Methods #######################################################################
onDidModelChange: ->
@refresh()
onDidRender: -> onDidRender: ->
@$message = @$('.message p') @$button = @$('.button')
@$count = @$('.count p') @$count = @$('.count p')
@$message = @$('.message p')
@$outdated = @$('.outdated')
@$waiting = @$('.waiting') @$waiting = @$('.waiting')
@_controls = [@$button, @$count, @$message, @$outdated, @$waiting]
super super
refresh: -> refresh: ->
@_refreshStatusText()
super
# Private Methods ##############################################################################
_refreshStatusText: ->
return unless @$message? and @$count? return unless @$message? and @$count?
@show @$waiting button = count = message = outdated = waiting = null
switch @model.stage switch @model.stage
when Craftsman::STAGE.WAITING when Craftsman::STAGE.READY
@$message.html 'Preparing crafting calculation...' message = 'Ready to compute crafting plan!'
@$count.html '' count = 'Click "Calculate" to continue.'
button = true
when Craftsman::STAGE.GRAPHING when Craftsman::STAGE.GRAPHING
@$message.html 'Researching recipes...' message = 'Researching recipes...'
@$count.html "Found #{@model.stageCount} recipes so far..." count = "Found #{@model.stageCount} recipes so far..."
watiing = true
when Craftsman::STAGE.PLANNING when Craftsman::STAGE.PLANNING
@$message.html 'Figuring out possible crafting plans...' message = 'Figuring out possible crafting plans...'
@$count.html "Found #{@model.stageCount} possibilities so far..." count = "Found #{@model.stageCount} possibilities so far..."
watiing = true
when Craftsman::STAGE.ANALYZING when Craftsman::STAGE.ANALYZING
@$message.html 'Looking for the best plan...' message = 'Looking for the best plan...'
@$count.html "Finished checking #{@model.stageCount} so far..." count = "Finished checking #{@model.stageCount} so far..."
watiing = true
when Craftsman::STAGE.COMPLETE when Craftsman::STAGE.COMPLETE
@$message.html 'All done!' message = 'Crafting plan is complete.'
@$count.html ''
when Craftsman::STAGE.INVALID when Craftsman::STAGE.INVALID
@$message.html 'Couldn\'t make a crafting plan' message = 'Couldn\'t make a crafting plan!'
@$count.html '' count = 'Please report this problem using the Feedback box.'
@hide @waiting 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 @onComplete = options.onComplete or (controller)-> # do nothing
@onAddTools = options.onAddTools 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 ################################################################################ # Event Methods ################################################################################
onCompleteButtonClicked: (event)-> onCompleteButtonClicked: (event)->
@@ -63,6 +70,9 @@ module.exports = class StepController extends BaseController
onWillChangeModel: (oldModel, newModel)-> onWillChangeModel: (oldModel, newModel)->
if not newModel? then throw new Error 'model cannot be null' if not newModel? then throw new Error 'model cannot be null'
if @rendered
@$el.removeClass 'complete'
@$completeButton.removeClass 'disabled'
return super return super
refresh: -> refresh: ->