mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
Stub WebSurface showing for web-dev levels
This commit is contained in:
parent
c5c831c211
commit
16b10612b6
16 changed files with 102 additions and 40 deletions
|
@ -19,6 +19,7 @@ var languagesImported = {};
|
||||||
|
|
||||||
var ensureLanguageImported = function(language) {
|
var ensureLanguageImported = function(language) {
|
||||||
if (languagesImported[language]) return;
|
if (languagesImported[language]) return;
|
||||||
|
if (language === 'html') return;
|
||||||
importScripts("/javascripts/app/vendor/aether-" + language + ".js");
|
importScripts("/javascripts/app/vendor/aether-" + language + ".js");
|
||||||
languagesImported[language] = true;
|
languagesImported[language] = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,7 +80,7 @@ var myImportScripts = importScripts;
|
||||||
var languagesImported = {};
|
var languagesImported = {};
|
||||||
var ensureLanguageImported = function(language) {
|
var ensureLanguageImported = function(language) {
|
||||||
if (languagesImported[language]) return;
|
if (languagesImported[language]) return;
|
||||||
if (language === 'javascript') return; // Only has JSHint, but we don't need to lint here.
|
if (language === 'javascript' || language === 'html') return; // Only has JSHint, but we don't need to lint here.
|
||||||
myImportScripts("/javascripts/app/vendor/aether-" + language + ".js");
|
myImportScripts("/javascripts/app/vendor/aether-" + language + ".js");
|
||||||
languagesImported[language] = true;
|
languagesImported[language] = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@ CocoModel = require 'models/CocoModel'
|
||||||
CocoCollection = require 'collections/CocoCollection'
|
CocoCollection = require 'collections/CocoCollection'
|
||||||
{me} = require('core/auth')
|
{me} = require('core/auth')
|
||||||
locale = require 'locale/locale'
|
locale = require 'locale/locale'
|
||||||
|
utils = require 'core/utils'
|
||||||
|
|
||||||
initializeFilePicker = ->
|
initializeFilePicker = ->
|
||||||
require('core/services/filepicker')() unless window.application.isIPadApp
|
require('core/services/filepicker')() unless window.application.isIPadApp
|
||||||
|
@ -234,21 +235,14 @@ class ImageFileTreema extends TreemaNode.nodeMap.string
|
||||||
@refreshDisplay()
|
@refreshDisplay()
|
||||||
|
|
||||||
|
|
||||||
codeLanguages =
|
|
||||||
javascript: 'ace/mode/javascript'
|
|
||||||
coffeescript: 'ace/mode/coffee'
|
|
||||||
python: 'ace/mode/python'
|
|
||||||
lua: 'ace/mode/lua'
|
|
||||||
java: 'ace/mode/java'
|
|
||||||
|
|
||||||
class CodeLanguagesObjectTreema extends TreemaNode.nodeMap.object
|
class CodeLanguagesObjectTreema extends TreemaNode.nodeMap.object
|
||||||
childPropertiesAvailable: ->
|
childPropertiesAvailable: ->
|
||||||
(key for key in _.keys(codeLanguages) when not @data[key]? and not (key is 'javascript' and @workingSchema.skipJavaScript))
|
(key for key in _.keys(utils.aceEditModes) when not @data[key]? and not (key is 'javascript' and @workingSchema.skipJavaScript))
|
||||||
|
|
||||||
class CodeLanguageTreema extends TreemaNode.nodeMap.string
|
class CodeLanguageTreema extends TreemaNode.nodeMap.string
|
||||||
buildValueForEditing: (valEl, data) ->
|
buildValueForEditing: (valEl, data) ->
|
||||||
super(valEl, data)
|
super(valEl, data)
|
||||||
valEl.find('input').autocomplete(source: _.keys(codeLanguages), minLength: 0, delay: 0, autoFocus: true)
|
valEl.find('input').autocomplete(source: _.keys(utils.aceEditModes), minLength: 0, delay: 0, autoFocus: true)
|
||||||
valEl
|
valEl
|
||||||
|
|
||||||
class CodeTreema extends TreemaNode.nodeMap.ace
|
class CodeTreema extends TreemaNode.nodeMap.ace
|
||||||
|
@ -256,8 +250,8 @@ class CodeTreema extends TreemaNode.nodeMap.ace
|
||||||
super(arguments...)
|
super(arguments...)
|
||||||
@workingSchema.aceTabSize = 4
|
@workingSchema.aceTabSize = 4
|
||||||
# TODO: Find a less hacky solution for this
|
# TODO: Find a less hacky solution for this
|
||||||
@workingSchema.aceMode = mode if mode = codeLanguages[@keyForParent]
|
@workingSchema.aceMode = mode if mode = utils.aceEditModes[@keyForParent]
|
||||||
@workingSchema.aceMode = mode if mode = codeLanguages[@parent?.data?.language]
|
@workingSchema.aceMode = mode if mode = utils.aceEditModes[@parent?.data?.language]
|
||||||
|
|
||||||
class CoffeeTreema extends CodeTreema
|
class CoffeeTreema extends CodeTreema
|
||||||
constructor: ->
|
constructor: ->
|
||||||
|
|
|
@ -259,7 +259,7 @@ startsWithVowel = (s) -> s[0] in 'aeiouAEIOU'
|
||||||
module.exports.filterMarkdownCodeLanguages = (text, language) ->
|
module.exports.filterMarkdownCodeLanguages = (text, language) ->
|
||||||
return '' unless text
|
return '' unless text
|
||||||
currentLanguage = language or me.get('aceConfig')?.language or 'python'
|
currentLanguage = language or me.get('aceConfig')?.language or 'python'
|
||||||
excludedLanguages = _.without ['javascript', 'python', 'coffeescript', 'clojure', 'lua', 'java', 'io'], currentLanguage
|
excludedLanguages = _.without ['javascript', 'python', 'coffeescript', 'clojure', 'lua', 'java', 'io', 'html'], currentLanguage
|
||||||
# Exclude language-specific code blocks like ```python (... code ...)``` for each non-target language.
|
# Exclude language-specific code blocks like ```python (... code ...)``` for each non-target language.
|
||||||
codeBlockExclusionRegex = new RegExp "```(#{excludedLanguages.join('|')})\n[^`]+```\n?", 'gm'
|
codeBlockExclusionRegex = new RegExp "```(#{excludedLanguages.join('|')})\n[^`]+```\n?", 'gm'
|
||||||
# Exclude language-specific images like ![python - image description](image url) for each non-target language.
|
# Exclude language-specific images like ![python - image description](image url) for each non-target language.
|
||||||
|
@ -290,12 +290,12 @@ module.exports.filterMarkdownCodeLanguages = (text, language) ->
|
||||||
return text
|
return text
|
||||||
|
|
||||||
module.exports.aceEditModes = aceEditModes =
|
module.exports.aceEditModes = aceEditModes =
|
||||||
'javascript': 'ace/mode/javascript'
|
javascript: 'ace/mode/javascript'
|
||||||
'coffeescript': 'ace/mode/coffee'
|
coffeescript: 'ace/mode/coffee'
|
||||||
'python': 'ace/mode/python'
|
python: 'ace/mode/python'
|
||||||
'java': 'ace/mode/java'
|
lua: 'ace/mode/lua'
|
||||||
'lua': 'ace/mode/lua'
|
java: 'ace/mode/java'
|
||||||
'java': 'ace/mode/java'
|
html: 'ace/mode/html'
|
||||||
|
|
||||||
module.exports.initializeACE = (el, codeLanguage) ->
|
module.exports.initializeACE = (el, codeLanguage) ->
|
||||||
contents = $(el).text().trim()
|
contents = $(el).text().trim()
|
||||||
|
|
|
@ -74,6 +74,8 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
onLevelLoaded: ->
|
onLevelLoaded: ->
|
||||||
if not @sessionless and @level.isType('hero', 'hero-ladder', 'hero-coop', 'course')
|
if not @sessionless and @level.isType('hero', 'hero-ladder', 'hero-coop', 'course')
|
||||||
@sessionDependenciesRegistered = {}
|
@sessionDependenciesRegistered = {}
|
||||||
|
if @level.isType('web-dev')
|
||||||
|
@headless = true
|
||||||
if (@courseID and not @level.isType('course', 'course-ladder')) or window.serverConfig.picoCTF
|
if (@courseID and not @level.isType('course', 'course-ladder')) or window.serverConfig.picoCTF
|
||||||
# Because we now use original hero levels for both hero and course levels, we fake being a course level in this context.
|
# Because we now use original hero levels for both hero and course levels, we fake being a course level in this context.
|
||||||
originalGet = @level.get
|
originalGet = @level.get
|
||||||
|
@ -481,6 +483,7 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
initWorld: ->
|
initWorld: ->
|
||||||
return if @initialized
|
return if @initialized
|
||||||
@initialized = true
|
@initialized = true
|
||||||
|
return if @level.isType('web-dev')
|
||||||
@world = new World()
|
@world = new World()
|
||||||
@world.levelSessionIDs = if @opponentSessionID then [@sessionID, @opponentSessionID] else [@sessionID]
|
@world.levelSessionIDs = if @opponentSessionID then [@sessionID, @opponentSessionID] else [@sessionID]
|
||||||
@world.submissionCount = @session?.get('state')?.submissionCount ? 0
|
@world.submissionCount = @session?.get('state')?.submissionCount ? 0
|
||||||
|
|
|
@ -61,7 +61,7 @@ _.extend CampaignSchema.properties, {
|
||||||
i18n: { type: 'object', format: 'hidden' }
|
i18n: { type: 'object', format: 'hidden' }
|
||||||
requiresSubscription: { type: 'boolean' }
|
requiresSubscription: { type: 'boolean' }
|
||||||
replayable: { type: 'boolean' }
|
replayable: { type: 'boolean' }
|
||||||
type: {'enum': ['ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']}
|
type: {'enum': ['ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev']}
|
||||||
slug: { type: 'string', format: 'hidden' }
|
slug: { type: 'string', format: 'hidden' }
|
||||||
original: { type: 'string', format: 'hidden' }
|
original: { type: 'string', format: 'hidden' }
|
||||||
adventurer: { type: 'boolean' }
|
adventurer: { type: 'boolean' }
|
||||||
|
|
|
@ -313,7 +313,7 @@ _.extend LevelSchema.properties,
|
||||||
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
||||||
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
||||||
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
||||||
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'])
|
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev'])
|
||||||
terrain: c.terrainString
|
terrain: c.terrainString
|
||||||
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
||||||
requiresSubscription: {title: 'Requires Subscription', description: 'Whether this level is available to subscribers only.', type: 'boolean'}
|
requiresSubscription: {title: 'Requires Subscription', description: 'Whether this level is available to subscribers only.', type: 'boolean'}
|
||||||
|
|
|
@ -272,6 +272,26 @@ $level-resize-transition-time: 0.5s
|
||||||
right: 45%
|
right: 45%
|
||||||
z-index: 1000000
|
z-index: 1000000
|
||||||
|
|
||||||
|
&.web-dev
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
bottom: 0
|
||||||
|
left: 0
|
||||||
|
right: 0
|
||||||
|
|
||||||
|
#playback-view, #thang-hud, #level-dialogue-view, #play-footer, #level-footer-background, #level-footer-shadow
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.game-container, .level-content, #game-area, #canvas-wrapper
|
||||||
|
height: 100%
|
||||||
|
|
||||||
|
#canvas-wrapper canvas
|
||||||
|
display: none
|
||||||
|
|
||||||
|
#web-surface
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
|
||||||
html.fullscreen-editor
|
html.fullscreen-editor
|
||||||
#level-view
|
#level-view
|
||||||
#fullscreen-editor-background-screen
|
#fullscreen-editor-background-screen
|
||||||
|
|
|
@ -24,6 +24,8 @@ if view.showAds()
|
||||||
#canvas-wrapper
|
#canvas-wrapper
|
||||||
canvas(width=924, height=589)#webgl-surface
|
canvas(width=924, height=589)#webgl-surface
|
||||||
canvas(width=924, height=589)#normal-surface
|
canvas(width=924, height=589)#normal-surface
|
||||||
|
|
||||||
|
#web-surface
|
||||||
#ascii-surface
|
#ascii-surface
|
||||||
#canvas-left-gradient.gradient
|
#canvas-left-gradient.gradient
|
||||||
#canvas-top-gradient.gradient
|
#canvas-top-gradient.gradient
|
||||||
|
|
|
@ -169,7 +169,7 @@ module.exports = class LevelLoadingView extends CocoView
|
||||||
@playSound 'loading-view-unveil', 0.5
|
@playSound 'loading-view-unveil', 0.5
|
||||||
@$el.find('.left-wing').css left: '-100%', backgroundPosition: 'right -400px top 0'
|
@$el.find('.left-wing').css left: '-100%', backgroundPosition: 'right -400px top 0'
|
||||||
@$el.find('.right-wing').css right: '-100%', backgroundPosition: 'left -400px top 0'
|
@$el.find('.right-wing').css right: '-100%', backgroundPosition: 'left -400px top 0'
|
||||||
$('#level-footer-background').detach().appendTo('#page-container').slideDown(duration)
|
$('#level-footer-background').detach().appendTo('#page-container').slideDown(duration) unless @level.isType('web-dev')
|
||||||
|
|
||||||
unveilIntro: =>
|
unveilIntro: =>
|
||||||
return if @destroyed or not @intro or @unveiled
|
return if @destroyed or not @intro or @unveiled
|
||||||
|
|
|
@ -132,7 +132,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
|
|
||||||
load: ->
|
load: ->
|
||||||
@loadStartTime = new Date()
|
@loadStartTime = new Date()
|
||||||
@god = new God({@gameUIState})
|
@god = new God({@gameUIState}) # TODO: don't make one of these in web-dev mode
|
||||||
levelLoaderOptions = supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @opponentSessionID, team: @getQueryVariable('team'), observing: @observing, courseID: @courseID
|
levelLoaderOptions = supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @opponentSessionID, team: @getQueryVariable('team'), observing: @observing, courseID: @courseID
|
||||||
if me.isSessionless()
|
if me.isSessionless()
|
||||||
levelLoaderOptions.fakeSessionConfig = {}
|
levelLoaderOptions.fakeSessionConfig = {}
|
||||||
|
@ -196,9 +196,12 @@ module.exports = class PlayLevelView extends RootView
|
||||||
|
|
||||||
grabLevelLoaderData: ->
|
grabLevelLoaderData: ->
|
||||||
@session = @levelLoader.session
|
@session = @levelLoader.session
|
||||||
@world = @levelLoader.world
|
|
||||||
@level = @levelLoader.level
|
@level = @levelLoader.level
|
||||||
@$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') # TODO: figure out what this does and comment it
|
if @level.isType('web-dev')
|
||||||
|
@$el.addClass 'web-dev' # Hide some of the elements we won't be using
|
||||||
|
return
|
||||||
|
@world = @levelLoader.world
|
||||||
|
@$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') # TODO: figure out what this does and comment it
|
||||||
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
|
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
|
||||||
# TODO: Update terminology to always be opponentSession or otherSession
|
# TODO: Update terminology to always be opponentSession or otherSession
|
||||||
# TODO: E.g. if it's always opponent right now, then variable names should be opponentSession until we have coop play
|
# TODO: E.g. if it's always opponent right now, then variable names should be opponentSession until we have coop play
|
||||||
|
@ -234,6 +237,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
@session.set('code', myCode)
|
@session.set('code', myCode)
|
||||||
|
|
||||||
setupGod: ->
|
setupGod: ->
|
||||||
|
return if @level.isType('web-dev')
|
||||||
@god.setLevel @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false}
|
@god.setLevel @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false}
|
||||||
@god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id]
|
@god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id]
|
||||||
@god.setWorldClassMap @world.classMap
|
@god.setWorldClassMap @world.classMap
|
||||||
|
@ -252,12 +256,12 @@ module.exports = class PlayLevelView extends RootView
|
||||||
|
|
||||||
insertSubviews: ->
|
insertSubviews: ->
|
||||||
@hintsState = new HintsState({ hidden: true }, { @session, @level })
|
@hintsState = new HintsState({ hidden: true }, { @session, @level })
|
||||||
@insertSubView @tome = new TomeView { @levelID, @session, @otherSession, thangs: @world.thangs, @supermodel, @level, @observing, @courseID, @courseInstanceID, @god, @hintsState }
|
@insertSubView @tome = new TomeView { @levelID, @session, @otherSession, thangs: @world?.thangs ? [], @supermodel, @level, @observing, @courseID, @courseInstanceID, @god, @hintsState }
|
||||||
@insertSubView new LevelPlaybackView session: @session, level: @level
|
@insertSubView new LevelPlaybackView session: @session, level: @level unless @level.isType('web-dev')
|
||||||
@insertSubView new GoalsView {level: @level}
|
@insertSubView new GoalsView {level: @level}
|
||||||
@insertSubView new LevelFlagsView levelID: @levelID, world: @world if @$el.hasClass 'flags'
|
@insertSubView new LevelFlagsView levelID: @levelID, world: @world if @$el.hasClass 'flags'
|
||||||
@insertSubView new GoldView {} unless @level.get('slug') in ['wakka-maul']
|
@insertSubView new GoldView {} unless @level.get('slug') in ['wakka-maul'] unless @level.isType('web-dev')
|
||||||
@insertSubView new HUDView {level: @level}
|
@insertSubView new HUDView {level: @level} unless @level.isType('web-dev')
|
||||||
@insertSubView new LevelDialogueView {level: @level, sessionID: @session.id}
|
@insertSubView new LevelDialogueView {level: @level, sessionID: @session.id}
|
||||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||||
@insertSubView new ProblemAlertView session: @session, level: @level, supermodel: @supermodel
|
@insertSubView new ProblemAlertView session: @session, level: @level, supermodel: @supermodel
|
||||||
|
@ -272,6 +276,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
Backbone.Mediator.publish 'level:set-volume', volume: volume
|
Backbone.Mediator.publish 'level:set-volume', volume: volume
|
||||||
|
|
||||||
initScriptManager: ->
|
initScriptManager: ->
|
||||||
|
return if @level.isType('web-dev')
|
||||||
@scriptManager = new ScriptManager({scripts: @world.scripts or [], view: @, session: @session, levelID: @level.get('slug')})
|
@scriptManager = new ScriptManager({scripts: @world.scripts or [], view: @, session: @session, levelID: @level.get('slug')})
|
||||||
@scriptManager.loadFromSession()
|
@scriptManager.loadFromSession()
|
||||||
|
|
||||||
|
@ -318,7 +323,10 @@ module.exports = class PlayLevelView extends RootView
|
||||||
@saveRecentMatch() if @otherSession
|
@saveRecentMatch() if @otherSession
|
||||||
@levelLoader.destroy()
|
@levelLoader.destroy()
|
||||||
@levelLoader = null
|
@levelLoader = null
|
||||||
@initSurface()
|
if @level.isType('web-dev')
|
||||||
|
@initWebSurface()
|
||||||
|
else
|
||||||
|
@initSurface()
|
||||||
|
|
||||||
saveRecentMatch: ->
|
saveRecentMatch: ->
|
||||||
allRecentlyPlayedMatches = storage.load('recently-played-matches') ? {}
|
allRecentlyPlayedMatches = storage.load('recently-played-matches') ? {}
|
||||||
|
@ -355,12 +363,13 @@ module.exports = class PlayLevelView extends RootView
|
||||||
# Once Surface is Loaded ####################################################
|
# Once Surface is Loaded ####################################################
|
||||||
|
|
||||||
onLevelStarted: ->
|
onLevelStarted: ->
|
||||||
return unless @surface?
|
return unless @surface? or @webSurface?
|
||||||
@loadingView.showReady()
|
@loadingView.showReady()
|
||||||
@trackLevelLoadEnd()
|
@trackLevelLoadEnd()
|
||||||
if window.currentModal and not window.currentModal.destroyed and window.currentModal.constructor isnt VictoryModal
|
if window.currentModal and not window.currentModal.destroyed and window.currentModal.constructor isnt VictoryModal
|
||||||
return Backbone.Mediator.subscribeOnce 'modal:closed', @onLevelStarted, @
|
return Backbone.Mediator.subscribeOnce 'modal:closed', @onLevelStarted, @
|
||||||
@surface.showLevel()
|
@surface?.showLevel()
|
||||||
|
@webSurface?.showLevel()
|
||||||
Backbone.Mediator.publish 'level:set-time', time: 0
|
Backbone.Mediator.publish 'level:set-time', time: 0
|
||||||
if (@isEditorPreview or @observing) and not @getQueryVariable('intro')
|
if (@isEditorPreview or @observing) and not @getQueryVariable('intro')
|
||||||
@loadingView.startUnveiling()
|
@loadingView.startUnveiling()
|
||||||
|
@ -406,7 +415,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
Backbone.Mediator.publish 'level:suppress-selection-sounds', suppress: true
|
Backbone.Mediator.publish 'level:suppress-selection-sounds', suppress: true
|
||||||
Backbone.Mediator.publish 'tome:select-primary-sprite', {}
|
Backbone.Mediator.publish 'tome:select-primary-sprite', {}
|
||||||
Backbone.Mediator.publish 'level:suppress-selection-sounds', suppress: false
|
Backbone.Mediator.publish 'level:suppress-selection-sounds', suppress: false
|
||||||
@surface.focusOnHero()
|
@surface?.focusOnHero()
|
||||||
|
|
||||||
perhapsStartSimulating: ->
|
perhapsStartSimulating: ->
|
||||||
return unless @shouldSimulate()
|
return unless @shouldSimulate()
|
||||||
|
@ -662,3 +671,11 @@ module.exports = class PlayLevelView extends RootView
|
||||||
@setupManager?.destroy()
|
@setupManager?.destroy()
|
||||||
@setupManager = new LevelSetupManager({supermodel: @supermodel, level: @level, levelID: @levelID, parent: @, session: @session, hadEverChosenHero: true})
|
@setupManager = new LevelSetupManager({supermodel: @supermodel, level: @level, levelID: @levelID, parent: @, session: @session, hadEverChosenHero: true})
|
||||||
@setupManager.open()
|
@setupManager.open()
|
||||||
|
|
||||||
|
|
||||||
|
# web-dev levels
|
||||||
|
initWebSurface: ->
|
||||||
|
@webSurface = showLevel: =>
|
||||||
|
# TODO: make a real WebSurface class
|
||||||
|
@$('#web-surface').css('background-color', 'red')
|
||||||
|
Backbone.Mediator.publish 'level:started', {}
|
||||||
|
|
|
@ -42,6 +42,7 @@ module.exports = class DocFormatter
|
||||||
@fillOutDoc()
|
@fillOutDoc()
|
||||||
|
|
||||||
fillOutDoc: ->
|
fillOutDoc: ->
|
||||||
|
# TODO: figure out how to do html docs for web-dev levels
|
||||||
if _.isString @doc
|
if _.isString @doc
|
||||||
@doc = name: @doc, type: typeof @options.thang[@doc]
|
@doc = name: @doc, type: typeof @options.thang[@doc]
|
||||||
if @options.isSnippet
|
if @options.isSnippet
|
||||||
|
|
|
@ -65,6 +65,7 @@ module.exports = class Spell
|
||||||
@worker = null
|
@worker = null
|
||||||
|
|
||||||
setLanguage: (@language) ->
|
setLanguage: (@language) ->
|
||||||
|
@language = 'html' if @level.isType('web-dev')
|
||||||
#console.log 'setting language to', @language, 'so using original source', @languages[language] ? @languages.javascript
|
#console.log 'setting language to', @language, 'so using original source', @languages[language] ? @languages.javascript
|
||||||
@originalSource = @languages[@language] ? @languages.javascript
|
@originalSource = @languages[@language] ? @languages.javascript
|
||||||
@originalSource = @addPicoCTFProblem() if window.serverConfig.picoCTF
|
@originalSource = @addPicoCTFProblem() if window.serverConfig.picoCTF
|
||||||
|
@ -126,6 +127,8 @@ module.exports = class Spell
|
||||||
else
|
else
|
||||||
source = @getSource()
|
source = @getSource()
|
||||||
[pure, problems] = [null, null]
|
[pure, problems] = [null, null]
|
||||||
|
if @language is 'html'
|
||||||
|
[pure, problems] = [source, []] # TODO: problems? Actually do something when transpiling
|
||||||
for thangID, spellThang of @thangs
|
for thangID, spellThang of @thangs
|
||||||
unless pure
|
unless pure
|
||||||
pure = spellThang.aether.transpile source
|
pure = spellThang.aether.transpile source
|
||||||
|
|
|
@ -55,6 +55,7 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
|
||||||
@buildDocs() unless @docsBuilt
|
@buildDocs() unless @docsBuilt
|
||||||
|
|
||||||
buildAvatar: ->
|
buildAvatar: ->
|
||||||
|
return unless @thang.world
|
||||||
avatar = new ThangAvatarView thang: @thang, includeName: false, supermodel: @supermodel
|
avatar = new ThangAvatarView thang: @thang, includeName: false, supermodel: @supermodel
|
||||||
if @avatar
|
if @avatar
|
||||||
@avatar.$el.replaceWith avatar.$el
|
@avatar.$el.replaceWith avatar.$el
|
||||||
|
|
|
@ -226,7 +226,7 @@ module.exports = class SpellView extends CocoView
|
||||||
disableSpaces = @options.level.get('disableSpaces') or false
|
disableSpaces = @options.level.get('disableSpaces') or false
|
||||||
aceConfig = me.get('aceConfig') ? {}
|
aceConfig = me.get('aceConfig') ? {}
|
||||||
disableSpaces = false if aceConfig.keyBindings and aceConfig.keyBindings isnt 'default' # Not in vim/emacs mode
|
disableSpaces = false if aceConfig.keyBindings and aceConfig.keyBindings isnt 'default' # Not in vim/emacs mode
|
||||||
disableSpaces = false if @spell.language in ['lua', 'java', 'coffeescript'] # Don't disable for more advanced/experimental languages
|
disableSpaces = false if @spell.language in ['lua', 'java', 'coffeescript', 'html'] # Don't disable for more advanced/experimental languages
|
||||||
if not disableSpaces or (_.isNumber(disableSpaces) and disableSpaces < me.level())
|
if not disableSpaces or (_.isNumber(disableSpaces) and disableSpaces < me.level())
|
||||||
return @ace.execCommand 'insertstring', ' '
|
return @ace.execCommand 'insertstring', ' '
|
||||||
line = @aceDoc.getLine @ace.getCursorPosition().row
|
line = @aceDoc.getLine @ace.getCursorPosition().row
|
||||||
|
@ -470,6 +470,7 @@ module.exports = class SpellView extends CocoView
|
||||||
# TODO: Turn on more autocompletion based on level sophistication
|
# TODO: Turn on more autocompletion based on level sophistication
|
||||||
# TODO: E.g. using the language default snippets yields a bunch of crazy non-beginner suggestions
|
# TODO: E.g. using the language default snippets yields a bunch of crazy non-beginner suggestions
|
||||||
# TODO: Options logic shouldn't exist both here and in updateAutocomplete()
|
# TODO: Options logic shouldn't exist both here and in updateAutocomplete()
|
||||||
|
return if @spell.language is 'html'
|
||||||
popupFontSizePx = @options.level.get('autocompleteFontSizePx') ? 16
|
popupFontSizePx = @options.level.get('autocompleteFontSizePx') ? 16
|
||||||
@zatanna = new Zatanna @ace,
|
@zatanna = new Zatanna @ace,
|
||||||
basic: false
|
basic: false
|
||||||
|
@ -864,7 +865,9 @@ module.exports = class SpellView extends CocoView
|
||||||
beginningOfLine = not currentLine.substr(0, cursorPosition.column).trim().length # uncommenting code, for example
|
beginningOfLine = not currentLine.substr(0, cursorPosition.column).trim().length # uncommenting code, for example
|
||||||
incompleteThis = /^(s|se|sel|self|t|th|thi|this)$/.test currentLine.trim()
|
incompleteThis = /^(s|se|sel|self|t|th|thi|this)$/.test currentLine.trim()
|
||||||
#console.log "finished=#{valid and (endOfLine or beginningOfLine) and not incompleteThis}", valid, endOfLine, beginningOfLine, incompleteThis, cursorPosition, currentLine.length, aether, new Date() - 0, currentLine
|
#console.log "finished=#{valid and (endOfLine or beginningOfLine) and not incompleteThis}", valid, endOfLine, beginningOfLine, incompleteThis, cursorPosition, currentLine.length, aether, new Date() - 0, currentLine
|
||||||
if valid and (endOfLine or beginningOfLine) and not incompleteThis
|
if @options.level.isType('web-dev') and valid
|
||||||
|
console.log 'Update it!'
|
||||||
|
else if valid and (endOfLine or beginningOfLine) and not incompleteThis
|
||||||
@preload()
|
@preload()
|
||||||
|
|
||||||
singleLineCommentRegex: ->
|
singleLineCommentRegex: ->
|
||||||
|
@ -976,8 +979,6 @@ module.exports = class SpellView extends CocoView
|
||||||
@ace.insert "{x=#{e.x}, y=#{e.y}}"
|
@ace.insert "{x=#{e.x}, y=#{e.y}}"
|
||||||
else
|
else
|
||||||
@ace.insert "{x: #{e.x}, y: #{e.y}}"
|
@ace.insert "{x: #{e.x}, y: #{e.y}}"
|
||||||
|
|
||||||
|
|
||||||
@highlightCurrentLine()
|
@highlightCurrentLine()
|
||||||
|
|
||||||
onStatementIndexUpdated: (e) ->
|
onStatementIndexUpdated: (e) ->
|
||||||
|
@ -1246,7 +1247,7 @@ module.exports = class SpellView extends CocoView
|
||||||
@debugView?.destroy()
|
@debugView?.destroy()
|
||||||
@translationView?.destroy()
|
@translationView?.destroy()
|
||||||
@toolbarView?.destroy()
|
@toolbarView?.destroy()
|
||||||
@zatanna.addSnippets [], @editorLang if @editorLang?
|
@zatanna?.addSnippets [], @editorLang if @editorLang?
|
||||||
$(window).off 'resize', @onWindowResize
|
$(window).off 'resize', @onWindowResize
|
||||||
window.clearTimeout @saveSpadeTimeout
|
window.clearTimeout @saveSpadeTimeout
|
||||||
@saveSpadeTimeout = null
|
@saveSpadeTimeout = null
|
||||||
|
|
|
@ -59,6 +59,9 @@ module.exports = class TomeView extends CocoView
|
||||||
super()
|
super()
|
||||||
@worker = @createWorker()
|
@worker = @createWorker()
|
||||||
programmableThangs = _.filter @options.thangs, (t) -> t.isProgrammable and t.programmableMethods
|
programmableThangs = _.filter @options.thangs, (t) -> t.isProgrammable and t.programmableMethods
|
||||||
|
if @options.level.isType('web-dev')
|
||||||
|
if @fakeProgrammableThang = @createFakeProgrammableThang()
|
||||||
|
programmableThangs = [@fakeProgrammableThang]
|
||||||
@createSpells programmableThangs, programmableThangs[0]?.world # Do before spellList, thangList, and castButton
|
@createSpells programmableThangs, programmableThangs[0]?.world # Do before spellList, thangList, and castButton
|
||||||
unless @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev')
|
unless @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev')
|
||||||
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel, level: @options.level
|
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel, level: @options.level
|
||||||
|
@ -140,7 +143,7 @@ module.exports = class TomeView extends CocoView
|
||||||
god: @options.god
|
god: @options.god
|
||||||
|
|
||||||
for thangID, spellKeys of @thangSpells
|
for thangID, spellKeys of @thangSpells
|
||||||
thang = world.getThangByID thangID
|
thang = @fakeProgrammableThang ? world.getThangByID thangID
|
||||||
if thang
|
if thang
|
||||||
@spells[spellKey].addThang thang for spellKey in spellKeys
|
@spells[spellKey].addThang thang for spellKey in spellKeys
|
||||||
else
|
else
|
||||||
|
@ -161,6 +164,7 @@ module.exports = class TomeView extends CocoView
|
||||||
@cast e?.preload, e?.realTime
|
@cast e?.preload, e?.realTime
|
||||||
|
|
||||||
cast: (preload=false, realTime=false) ->
|
cast: (preload=false, realTime=false) ->
|
||||||
|
return if @options.level.isType('web-dev')
|
||||||
sessionState = @options.session.get('state') ? {}
|
sessionState = @options.session.get('state') ? {}
|
||||||
if realTime
|
if realTime
|
||||||
sessionState.submissionCount = (sessionState.submissionCount ? 0) + 1
|
sessionState.submissionCount = (sessionState.submissionCount ? 0) + 1
|
||||||
|
@ -194,7 +198,7 @@ module.exports = class TomeView extends CocoView
|
||||||
@castButton?.$el.hide()
|
@castButton?.$el.hide()
|
||||||
|
|
||||||
onSpriteSelected: (e) ->
|
onSpriteSelected: (e) ->
|
||||||
return if @spellView and @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'] # Never deselect the hero in the Tome.
|
return if @spellView and @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev'] # Never deselect the hero in the Tome.
|
||||||
thang = e.thang
|
thang = e.thang
|
||||||
spellName = e.spellName
|
spellName = e.spellName
|
||||||
@spellList?.$el.hide()
|
@spellList?.$el.hide()
|
||||||
|
@ -204,6 +208,9 @@ module.exports = class TomeView extends CocoView
|
||||||
@clearSpellView()
|
@clearSpellView()
|
||||||
@updateSpellPalette thang, spell if spell
|
@updateSpellPalette thang, spell if spell
|
||||||
return
|
return
|
||||||
|
@setSpellView spell, thang
|
||||||
|
|
||||||
|
setSpellView: (spell, thang) ->
|
||||||
unless spell.view is @spellView
|
unless spell.view is @spellView
|
||||||
@clearSpellView()
|
@clearSpellView()
|
||||||
@spellView = spell.view
|
@spellView = spell.view
|
||||||
|
@ -246,6 +253,9 @@ module.exports = class TomeView extends CocoView
|
||||||
@cast()
|
@cast()
|
||||||
|
|
||||||
onSelectPrimarySprite: (e) ->
|
onSelectPrimarySprite: (e) ->
|
||||||
|
if @options.level.isType('web-dev')
|
||||||
|
@setSpellView @spells['hero-placeholder/plan'], @fakeProgrammableThang
|
||||||
|
return
|
||||||
# This is only fired by PlayLevelView for hero levels currently
|
# This is only fired by PlayLevelView for hero levels currently
|
||||||
# TODO: Don't hard code these hero names
|
# TODO: Don't hard code these hero names
|
||||||
if @options.session.get('team') is 'ogres'
|
if @options.session.get('team') is 'ogres'
|
||||||
|
@ -253,6 +263,15 @@ module.exports = class TomeView extends CocoView
|
||||||
else
|
else
|
||||||
Backbone.Mediator.publish 'level:select-sprite', thangID: 'Hero Placeholder'
|
Backbone.Mediator.publish 'level:select-sprite', thangID: 'Hero Placeholder'
|
||||||
|
|
||||||
|
createFakeProgrammableThang: ->
|
||||||
|
return null unless hero = _.find @options.level.get('thangs'), id: 'Hero Placeholder'
|
||||||
|
return null unless programmableConfig = _.find(hero.components, (component) -> component.config?.programmableMethods).config
|
||||||
|
thang =
|
||||||
|
id: 'Hero Placeholder'
|
||||||
|
isProgrammable: true
|
||||||
|
thang = _.merge thang, programmableConfig
|
||||||
|
thang
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
spell.destroy() for spellKey, spell of @spells
|
spell.destroy() for spellKey, spell of @spells
|
||||||
@worker?.terminate()
|
@worker?.terminate()
|
||||||
|
|
Loading…
Reference in a new issue