2014-01-03 13:32:13 -05:00
|
|
|
# There's one TomeView per Level. It has:
|
|
|
|
# - a CastButtonView, which has
|
|
|
|
# - a cast button
|
|
|
|
# - an autocast settings options button
|
|
|
|
# - for each spell (programmableMethod):
|
|
|
|
# - a Spell, which has
|
|
|
|
# - a list of Thangs that share that Spell, with one aether per Thang per Spell
|
|
|
|
# - a SpellView, which has
|
|
|
|
# - tons of stuff; the meat
|
|
|
|
# - a SpellListView, which has
|
|
|
|
# - for each spell:
|
|
|
|
# - a SpellListEntryView, which has
|
|
|
|
# - icons for each Thang
|
|
|
|
# - the spell name
|
|
|
|
# - a reload button
|
|
|
|
# - documentation for that method (in a popover)
|
|
|
|
# - a SpellPaletteView, which has
|
|
|
|
# - for each programmableProperty:
|
|
|
|
# - a SpellPaletteEntryView
|
|
|
|
#
|
|
|
|
# The CastButtonView and SpellListView always show.
|
|
|
|
# The SpellPaletteView shows the entries for the currently selected Programmable Thang.
|
|
|
|
# The SpellView shows the code and runtime state for the currently selected Spell and, specifically, Thang.
|
|
|
|
# The SpellView obscures most of the SpellListView when present. We might mess with this.
|
|
|
|
# You can switch a SpellView to showing the runtime state of another Thang sharing that Spell.
|
|
|
|
# SpellPaletteViews are destroyed and recreated whenever you switch Thangs.
|
|
|
|
# The SpellListView shows spells to which your team has read or readwrite access.
|
|
|
|
# It doubles as a Thang selector, since it's there when nothing is selected.
|
|
|
|
|
|
|
|
View = require 'views/kinds/CocoView'
|
|
|
|
template = require 'templates/play/level/tome/tome'
|
|
|
|
{me} = require 'lib/auth'
|
|
|
|
Spell = require './spell'
|
|
|
|
SpellListView = require './spell_list_view'
|
|
|
|
ThangListView = require './thang_list_view'
|
|
|
|
SpellPaletteView = require './spell_palette_view'
|
|
|
|
CastButtonView = require './cast_button_view'
|
|
|
|
|
|
|
|
module.exports = class TomeView extends View
|
|
|
|
id: 'tome-view'
|
|
|
|
template: template
|
|
|
|
controlsEnabled: true
|
|
|
|
cache: false
|
|
|
|
|
|
|
|
subscriptions:
|
|
|
|
'tome:spell-loaded': "onSpellLoaded"
|
|
|
|
'tome:cast-spell': "onCastSpell"
|
|
|
|
'tome:toggle-spell-list': 'onToggleSpellList'
|
|
|
|
'surface:sprite-selected': 'onSpriteSelected'
|
2014-02-05 18:16:59 -05:00
|
|
|
'god:new-world-created': 'onNewWorld'
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
events:
|
|
|
|
'click #spell-view': 'onSpellViewClick'
|
|
|
|
'click': -> Backbone.Mediator.publish 'focus-editor'
|
|
|
|
|
|
|
|
afterRender: ->
|
|
|
|
super()
|
|
|
|
programmableThangs = _.filter @options.thangs, 'isProgrammable'
|
2014-01-16 17:29:57 -05:00
|
|
|
|
2014-01-16 16:18:38 -05:00
|
|
|
if programmableThangs.length
|
2014-02-05 18:16:59 -05:00
|
|
|
@createSpells programmableThangs, programmableThangs[0].world # Do before spellList, thangList, and castButton
|
2014-01-16 16:22:42 -05:00
|
|
|
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
|
|
|
|
@thangList = @insertSubView new ThangListView spells: @spells, thangs: @options.thangs, supermodel: @supermodel
|
|
|
|
@castButton = @insertSubView new CastButtonView spells: @spells
|
2014-01-16 16:18:38 -05:00
|
|
|
else
|
|
|
|
@cast()
|
2014-02-05 18:54:34 -05:00
|
|
|
console.warn "Warning: There are no Programmable Thangs in this level, which makes it unplayable."
|
2014-02-06 17:00:27 -05:00
|
|
|
delete @options.thangs
|
2014-01-03 13:32:13 -05:00
|
|
|
|
2014-02-05 18:16:59 -05:00
|
|
|
onNewWorld: (e) ->
|
2014-02-05 23:08:28 -05:00
|
|
|
thangs = _.filter e.world.thangs, 'isSelectable'
|
|
|
|
programmableThangs = _.filter thangs, 'isProgrammable'
|
|
|
|
@createSpells programmableThangs, e.world
|
|
|
|
@thangList.adjustThangs @spells, thangs
|
2014-02-05 18:16:59 -05:00
|
|
|
@spellList.adjustSpells @spells
|
2014-01-29 13:14:12 -05:00
|
|
|
|
2014-02-05 18:16:59 -05:00
|
|
|
createSpells: (programmableThangs, world) ->
|
2014-01-03 13:32:13 -05:00
|
|
|
pathPrefixComponents = ['play', 'level', @options.levelID, @options.session.id, 'code']
|
2014-01-29 13:14:12 -05:00
|
|
|
@spells ?= {}
|
|
|
|
@thangSpells ?= {}
|
2014-01-03 13:32:13 -05:00
|
|
|
for thang in programmableThangs
|
2014-01-29 13:14:12 -05:00
|
|
|
continue if @thangSpells[thang.id]?
|
2014-01-03 13:32:13 -05:00
|
|
|
@thangSpells[thang.id] = []
|
|
|
|
for methodName, method of thang.programmableMethods
|
|
|
|
pathComponents = [thang.id, methodName]
|
|
|
|
if method.cloneOf
|
|
|
|
pathComponents[0] = method.cloneOf # referencing another Thang's method
|
|
|
|
pathComponents[0] = _.string.slugify pathComponents[0]
|
|
|
|
spellKey = pathComponents.join '/'
|
|
|
|
@thangSpells[thang.id].push spellKey
|
|
|
|
unless method.cloneOf
|
2014-01-28 18:24:08 -05:00
|
|
|
spell = @spells[spellKey] = new Spell programmableMethod: method, spellKey: spellKey, pathComponents: pathPrefixComponents.concat(pathComponents), session: @options.session, supermodel: @supermodel, skipFlow: @getQueryVariable("skip_flow") is "true", skipProtectAPI: @getQueryVariable("skip_protect_api") is "true"
|
2014-01-03 13:32:13 -05:00
|
|
|
for thangID, spellKeys of @thangSpells
|
2014-02-05 18:16:59 -05:00
|
|
|
thang = world.getThangByID thangID
|
|
|
|
if thang
|
|
|
|
@spells[spellKey].addThang thang for spellKey in spellKeys
|
|
|
|
else
|
|
|
|
delete @thangSpells[thangID]
|
2014-02-06 17:00:27 -05:00
|
|
|
spell.removeThangID thangID for spell in @spells
|
2014-01-03 13:32:13 -05:00
|
|
|
null
|
|
|
|
|
|
|
|
onSpellLoaded: (e) ->
|
|
|
|
for spellID, spell of @spells
|
|
|
|
return unless spell.loaded
|
|
|
|
@cast()
|
|
|
|
|
|
|
|
onCastSpell: (e) ->
|
|
|
|
# A single spell is cast.
|
|
|
|
# Hmm; do we need to make sure other spells are all cast here?
|
|
|
|
@cast()
|
|
|
|
|
|
|
|
cast: ->
|
|
|
|
Backbone.Mediator.publish 'tome:cast-spells', spells: @spells
|
|
|
|
|
|
|
|
onToggleSpellList: (e) ->
|
|
|
|
@spellList.$el.toggle()
|
|
|
|
|
|
|
|
onSpellViewClick: (e) ->
|
|
|
|
@spellList.$el.hide()
|
|
|
|
|
|
|
|
clearSpellView: ->
|
|
|
|
@spellView?.dismiss()
|
|
|
|
@spellView?.$el.after('<div id="' + @spellView.id + '"></div>').detach()
|
|
|
|
@spellView = null
|
|
|
|
@spellTabView?.$el.after('<div id="' + @spellTabView.id + '"></div>').detach()
|
|
|
|
@spellTabView = null
|
|
|
|
@removeSubView @spellPaletteView if @spellPaletteView
|
2014-02-02 13:26:42 -05:00
|
|
|
@spellPaletteView = null
|
2014-01-21 12:03:04 -05:00
|
|
|
@castButton?.$el.hide()
|
2014-01-16 17:29:57 -05:00
|
|
|
@thangList?.$el.show()
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
onSpriteSelected: (e) ->
|
|
|
|
thang = e.thang
|
|
|
|
spellName = e.spellName
|
2014-01-16 17:29:57 -05:00
|
|
|
@spellList?.$el.hide()
|
2014-01-03 13:32:13 -05:00
|
|
|
return @clearSpellView() unless thang?.isProgrammable
|
|
|
|
selectedThangSpells = (@spells[spellKey] for spellKey in @thangSpells[thang.id])
|
|
|
|
if spellName
|
|
|
|
spell = _.find selectedThangSpells, {name: spellName}
|
|
|
|
else
|
|
|
|
spell = @thangList.topSpellForThang thang
|
|
|
|
#spell = selectedThangSpells[0] # TODO: remember last selected spell for this thang
|
|
|
|
return @clearSpellView() unless spell?.canRead()
|
2014-02-02 13:26:42 -05:00
|
|
|
unless spell.view is @spellView
|
|
|
|
@clearSpellView()
|
|
|
|
@spellView = spell.view
|
|
|
|
@spellTabView = spell.tabView
|
|
|
|
@$el.find('#' + @spellView.id).after(@spellView.el).remove()
|
|
|
|
@$el.find('#' + @spellTabView.id).after(@spellTabView.el).remove()
|
|
|
|
@castButton.attachTo @spellView
|
|
|
|
@thangList.$el.hide()
|
|
|
|
Backbone.Mediator.publish 'tome:spell-shown', thang: thang, spell: spell
|
2014-01-03 13:32:13 -05:00
|
|
|
@spellList.setThangAndSpell thang, spell
|
2014-01-31 19:16:59 -05:00
|
|
|
@spellView?.setThang thang
|
|
|
|
@spellTabView?.setThang thang
|
|
|
|
if @spellPaletteView?.thang isnt thang
|
|
|
|
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang
|
|
|
|
@spellPaletteView.toggleControls {}, spell.view.controlsEnabled # TODO: know when palette should have been disabled but didn't exist
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
|
|
reloadAllCode: ->
|
|
|
|
spell.view.reloadCode false for spellKey, spell of @spells
|
|
|
|
Backbone.Mediator.publish 'tome:cast-spells', spells: @spells
|
|
|
|
|
|
|
|
destroy: ->
|
|
|
|
super()
|
|
|
|
for spellKey, spell of @spells
|
|
|
|
spell.view.destroy()
|