codecombat/app/views/play/level/tome/spell.coffee

169 lines
6.4 KiB
CoffeeScript
Raw Normal View History

2014-01-03 13:32:13 -05:00
SpellView = require './spell_view'
SpellListTabEntryView = require './spell_list_tab_entry_view'
{me} = require 'lib/auth'
2014-05-08 14:43:00 -04:00
Aether.addGlobal 'Vector', require 'lib/world/vector'
Aether.addGlobal '_', _
2014-01-03 13:32:13 -05:00
module.exports = class Spell
loaded: false
view: null
entryView: null
2014-01-28 18:24:08 -05:00
constructor: (options) ->
@spellKey = options.spellKey
@pathComponents = options.pathComponents
@session = options.session
@spectateView = options.spectateView
2014-01-28 18:24:08 -05:00
@supermodel = options.supermodel
@skipProtectAPI = options.skipProtectAPI
@worker = options.worker
2014-01-28 18:24:08 -05:00
p = options.programmableMethod
@languages = p.languages ? {}
@languages.javascript ?= p.source
2014-01-03 13:32:13 -05:00
@name = p.name
@permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams
@setLanguage if @canWrite() then options.language else 'javascript'
@useTranspiledCode = @shouldUseTranspiledCode()
@source = @originalSource
2014-04-26 17:21:26 -04:00
@parameters = p.parameters
if @permissions.readwrite.length and sessionSource = @session.getSourceFor(@spellKey)
@source = sessionSource
2014-01-03 13:32:13 -05:00
@thangs = {}
@view = new SpellView {spell: @, session: @session, worker: @worker}
2014-01-03 13:32:13 -05:00
@view.render() # Get it ready and code loaded in advance
@tabView = new SpellListTabEntryView spell: @, supermodel: @supermodel, language: @language
2014-01-03 13:32:13 -05:00
@tabView.render()
@team = @permissions.readwrite[0] ? "common"
Backbone.Mediator.publish 'tome:spell-created', spell: @
2014-01-03 13:32:13 -05:00
2014-02-11 15:10:21 -05:00
destroy: ->
@view.destroy()
@tabView.destroy()
2014-02-11 18:38:36 -05:00
@thangs = null
@worker = null
setLanguage: (@language) ->
@originalSource = @languages[language] ? @languages.javascript
2014-01-03 13:32:13 -05:00
addThang: (thang) ->
if @thangs[thang.id]
@thangs[thang.id].thang = thang
else
@thangs[thang.id] = {thang: thang, aether: @createAether(thang), castAether: null}
2014-01-03 13:32:13 -05:00
removeThangID: (thangID) ->
delete @thangs[thangID]
2014-01-03 13:32:13 -05:00
canRead: (team) ->
(team ? me.team) in @permissions.read or (team ? me.team) in @permissions.readwrite
canWrite: (team) ->
(team ? me.team) in @permissions.readwrite
getSource: ->
@view.getSource()
transpile: (source) ->
if source
@source = source
else
source = @getSource()
[pure, problems] = [null, null]
if @useTranspiledCode
transpiledCode = @session.get('code')
for thangID, spellThang of @thangs
unless pure
if @useTranspiledCode and transpiledSpell = transpiledCode[@spellKey.split('/')[0]]?[@name]
spellThang.aether.pure = transpiledSpell
else
pure = spellThang.aether.transpile source
problems = spellThang.aether.problems
#console.log "aether transpiled", source.length, "to", spellThang.aether.pure.length, "for", thangID, @spellKey
else
spellThang.aether.pure = pure
spellThang.aether.problems = problems
#console.log "aether reused transpilation for", thangID, @spellKey
null
2014-01-03 13:32:13 -05:00
hasChanged: (newSource=null, currentSource=null) ->
(newSource ? @originalSource) isnt (currentSource ? @source)
hasChangedSignificantly: (newSource=null, currentSource=null, cb) ->
2014-01-03 13:32:13 -05:00
for thangID, spellThang of @thangs
aether = spellThang.aether
break
unless aether
console.error @toString(), "couldn't find a spellThang with aether of", @thangs
2014-04-22 14:04:56 -04:00
cb false
workerMessage =
function: "hasChangedSignificantly"
a: (newSource ? @originalSource)
spellKey: @spellKey
b: (currentSource ? @source)
careAboutLineNumbers: true
careAboutLint: true
@worker.addEventListener "message", (e) =>
workerData = JSON.parse e.data
2014-04-22 14:04:56 -04:00
if workerData.function is "hasChangedSignificantly" and workerData.spellKey is @spellKey
@worker.removeEventListener "message", arguments.callee, false
cb(workerData.hasChanged)
@worker.postMessage JSON.stringify(workerMessage)
2014-04-26 17:21:26 -04:00
2014-01-03 13:32:13 -05:00
createAether: (thang) ->
aceConfig = me.get('aceConfig') ? {}
writable = @permissions.readwrite.length > 0
2014-01-03 13:32:13 -05:00
aetherOptions =
problems:
jshint_W040: {level: "ignore"}
jshint_W030: {level: "ignore"} # aether_NoEffect instead
2014-04-14 14:18:02 -04:00
jshint_W038: {level: "ignore"} # eliminates hoisting problems
jshint_W091: {level: "ignore"} # eliminates more hoisting problems
jshint_E043: {level: "ignore"} # https://github.com/codecombat/codecombat/issues/813 -- since we can't actually tell JSHint to really ignore things
jshint_Unknown: {level: "ignore"} # E043 also triggers Unknown, so ignore that, too
2014-05-08 14:43:00 -04:00
aether_MissingThis: {level: 'error'}
language: if @canWrite() then @language else 'javascript'
2014-01-03 13:32:13 -05:00
functionName: @name
functionParameters: @parameters
yieldConditionally: thang.plan?
2014-05-08 14:43:00 -04:00
globals: ['Vector', '_']
2014-01-29 11:38:37 -05:00
# TODO: Gridmancer doesn't currently work with protectAPI, so hack it off
protectAPI: not (@skipProtectAPI or window.currentView?.level.get('name').match("Gridmancer")) and writable # If anyone can write to this method, we must protect it.
includeFlow: false
executionLimit: 1 * 1000 * 1000
#console.log "creating aether with options", aetherOptions
2014-01-03 13:32:13 -05:00
aether = new Aether aetherOptions
workerMessage =
function: "createAether"
spellKey: @spellKey
options: aetherOptions
@worker.postMessage JSON.stringify workerMessage
2014-01-03 13:32:13 -05:00
aether
updateLanguageAether: (@language) ->
for thangId, spellThang of @thangs
spellThang.aether?.setLanguage @language
spellThang.castAether = null
Backbone.Mediator.publish 'tome:spell-changed-language', spell: @, language: @language
2014-04-26 17:21:26 -04:00
workerMessage =
function: "updateLanguageAether"
newLanguage: @language
@worker.postMessage JSON.stringify workerMessage
@transpile()
2014-01-03 13:32:13 -05:00
toString: ->
"<Spell: #{@spellKey}>"
shouldUseTranspiledCode: ->
# Determine whether this code has already been transpiled, or whether it's raw source needing transpilation.
return false unless @permissions.readwrite.length # Only player-writable code will be stored transpiled.
return true if @spectateView # Use transpiled code for both teams if we're just spectating.
teamSpells = @session.get('teamSpells')
team = @session.get('team') ? 'humans'
return true if teamSpells and not _.contains(teamSpells[team], @spellKey) # Use transpiled for enemy spells.
# Players without permissions can't view the raw code.
return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions'))
false