Add picoCTF problem descriptions to levels; streamline picoCTF flows more

This commit is contained in:
Nick Winter 2016-02-17 11:33:50 -08:00
parent 0905a378a0
commit b5bb662ed2
13 changed files with 100 additions and 14 deletions

View file

@ -64,6 +64,10 @@ module.exports = class LevelLoader extends CocoClass
@level.get = ->
return 'course' if arguments[0] is 'type'
originalGet.apply @, arguments
if window.serverConfig.picoCTF
@supermodel.addRequestResource(url: '/picoctf/problems', success: (picoCTFProblems) =>
@level?.picoCTFProblem = _.find picoCTFProblems, pid: @level.get('picoCTFProblem')
).load()
@loadSession() unless @sessionless
@populateLevel()

View file

@ -1,7 +1,7 @@
@import "app/styles/mixins"
@import "app/styles/bootstrap/variables"
#course-victory-modal
#course-victory-modal, #picoctf-victory-modal
//- Top-level modal container
.modal-dialog
@ -62,7 +62,7 @@
html.no-borderimage
#course-victory-modal
#course-victory-modal, #picoctf-victory-modal
.modal-dialog
margin-top: 251px
.background-wrapper

View file

@ -44,6 +44,6 @@
if !me.get('anonymous')
#play-footer(class=me.isPremium() ? "premium" : "")
p(class='footer-link-text')
p(class='footer-link-text').picoctf-hide
a.contact-link(title='Send CodeCombat a message', tabindex=-1, data-i18n="nav.contact") Contact

View file

@ -33,7 +33,7 @@
span(data-i18n="courses.course_membership_required_to_play") You'll need to join a course to play this level.
a.btn.btn-lg.btn-warning(data-i18n="courses.go_to_courses", href="/courses") Go To Courses
#tip-wrapper
#tip-wrapper.picoctf-hide
strong.tip(data-i18n='play_level.tip_toggle_play') Toggle play/paused with Ctrl+P.
strong.tip(data-i18n='play_level.tip_scrub_shortcut') Ctrl+[ and Ctrl+] rewind and fast-forward.
strong.tip(data-i18n='play_level.tip_guide_exists') Click the guide, inside game menu (at the top of the page), for useful info.

View file

@ -0,0 +1,26 @@
.modal-dialog
.background-wrapper
.modal-content
.modal-header
#close-modal.well.well-sm.well-parchment(data-dismiss="modal")
span.glyphicon.glyphicon-remove
#victory-header
#victory-title
if !me.get('preferredLanguage') || me.get('preferredLanguage').split('-')[0] == 'en'
img(src="/images/pages/play/level/modal/victory_word.png", draggable="false")
else
h1(data-i18n="play_level.victory") Victory
.modal-body
.container-fluid
.row
- var victoryText = view.level.get('victory');
- victoryText = {body: 'You have gotten busted'}
if victoryText && victoryText.body
.well.well-sm.well-parchment
h3= victoryText.body
.row
.col-sm-5.col-sm-offset-2
.col-sm-5
a(href="/play/picoctf")#done-btn.btn.btn-illustrated.btn-primary.btn-block.btn-lg.text-uppercase Done

View file

@ -71,7 +71,7 @@ module.exports = class CampaignView extends RootView
@levelPlayCountMap = {}
@levelDifficultyMap = {}
if window.serverConfig.picoCTF
@supermodel.addRequestResource(url: '/picoctf/problems', success: @onPicoCTFProblemsLoaded).load()
@supermodel.addRequestResource(url: '/picoctf/problems', success: (@picoCTFProblems) =>).load()
else
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
@listenToOnce @sessions, 'sync', @onSessionsLoaded
@ -280,7 +280,7 @@ module.exports = class CampaignView extends RootView
level.locked = false if problem.unlocked
level.description = """
### #{problem.name}
#{problem.description}
#{level.description or problem.description}
#{problem.category} - #{problem.score} points
""" # Skipping #{problem.hints}
@ -439,8 +439,6 @@ module.exports = class CampaignView extends RootView
onCampaignsLoaded: (e) ->
@render()
onPicoCTFProblemsLoaded: (@picoCTFProblems) =>
preloadLevel: (levelSlug) ->
levelURL = "/db/level/#{levelSlug}"
level = new Level().setURL levelURL

View file

@ -85,7 +85,7 @@ module.exports = class ControlBarView extends CocoView
@homeViewArgs.push leagueType
@homeViewArgs.push leagueID
@homeLink += "/#{leagueType}/#{leagueID}"
else if @level.get('type', true) in ['hero', 'hero-coop']
else if @level.get('type', true) in ['hero', 'hero-coop'] or window.serverConfig.picoCTF
@homeLink = '/play'
@homeViewClass = 'views/play/CampaignView'
campaign = @level.get 'campaign'

View file

@ -78,6 +78,8 @@ module.exports = class LevelLoadingView extends CocoView
@docs = @level.get('documentation') ? {}
specific = @docs.specificArticles or []
@intro = _.find specific, name: 'Intro'
if window.serverConfig.picoCTF
@intro ?= body: ''
showReady: ->
return if @shownReady
@ -170,7 +172,18 @@ module.exports = class LevelLoadingView extends CocoView
unveilIntro: =>
return if @destroyed or not @intro or @unveiled
html = marked utils.filterMarkdownCodeLanguages(utils.i18n(@intro, 'body'))
if window.serverConfig.picoCTF and problem = @level.picoCTFProblem
html = marked """
### #{problem.name}
#{@intro.body}
#{problem.description}
#{problem.category} - #{problem.score} points
""", sanitize: false
else
html = marked utils.filterMarkdownCodeLanguages(utils.i18n(@intro, 'body'))
@$el.find('.intro-doc').removeClass('hidden').find('.intro-doc-content').html html
@resize()
@ -194,7 +207,7 @@ module.exports = class LevelLoadingView extends CocoView
onClickStartSubscription: (e) ->
@openModalView new SubscribeModal()
levelSlug = @level?.get('slug') or @options.level?.get('slug')
# TODO: Added levelID on 2/9/16. Remove level property and associated AnalyticsLogEvent 'properties.level' index later.
# TODO: Added levelID on 2/9/16. Remove level property and associated AnalyticsLogEvent 'properties.level' index later.
window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'level loading', level: levelSlug, levelID: levelSlug
onSubscribed: ->

View file

@ -37,6 +37,7 @@ DuelStatsView = require './DuelStatsView'
VictoryModal = require './modal/VictoryModal'
HeroVictoryModal = require './modal/HeroVictoryModal'
CourseVictoryModal = require './modal/CourseVictoryModal'
PicoCTFVictoryModal = require './modal/PicoCTFVictoryModal'
InfiniteLoopModal = require './modal/InfiniteLoopModal'
LevelSetupManager = require 'lib/LevelSetupManager'
ContactModal = require 'views/core/ContactModal'
@ -535,6 +536,7 @@ module.exports = class PlayLevelView extends RootView
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID}
ModalClass = if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder'] then HeroVictoryModal else VictoryModal
ModalClass = CourseVictoryModal if @courseID and @courseInstanceID
ModalClass = PicoCTFVictoryModal if window.serverConfig.picoCTF
victoryModal = new ModalClass(options)
@openModalView(victoryModal)
if me.get('anonymous')

View file

@ -0,0 +1,18 @@
ModalView = require 'views/core/ModalView'
template = require 'templates/play/level/modal/picoctf-victory-modal'
module.exports = class PicoCTFVictoryModal extends ModalView
id: 'picoctf-victory-modal'
template: template
closesOnClickOutside: false
initialize: (options) ->
@session = options.session
@level = options.level
# TODO: submit to picoCTF server
@playSound 'victory'
onLoaded: ->
super()

View file

@ -21,6 +21,7 @@ module.exports = class Spell
@worker = options.worker
@levelID = options.levelID
@levelType = options.level.get('type', true)
@level = options.level
p = options.programmableMethod
@commentI18N = p.i18n
@ -63,6 +64,7 @@ module.exports = class Spell
setLanguage: (@language) ->
#console.log 'setting language to', @language, 'so using original source', @languages[language] ? @languages.javascript
@originalSource = @languages[@language] ? @languages.javascript
@originalSource = @addPicoCTFProblem() if window.serverConfig.picoCTF
# Translate comments chosen spoken language.
return unless @commentContext
@ -91,6 +93,14 @@ module.exports = class Spell
when 'io' then @originalSource.replace /loop\n/, 'while true,\n'
else @originalSource
addPicoCTFProblem: ->
return unless problem = @level.picoCTFProblem
description = """
-- #{problem.name} --
#{problem.description}
""".replace /<p>(.*?)<\/p>/gi, '$1'
("// #{line}" for line in description.split('\n')).join('\n') + '\n' + @originalSource
addThang: (thang) ->
if @thangs[thang.id]
@thangs[thang.id].thang = thang

View file

@ -32,7 +32,7 @@ module.exports = class GameMenuModal extends ModalView
context = super(context)
docs = @options.level.get('documentation') ? {}
submenus = ['guide', 'options', 'save-load', 'multiplayer']
submenus = _.without submenus, 'guide' unless docs.specificArticles?.length or docs.generalArticles?.length
submenus = _.without submenus, 'guide' unless docs.specificArticles?.length or docs.generalArticles?.length or window.serverConfig.picoCTF
submenus = _.without submenus, 'save-load' unless me.isAdmin() or /https?:\/\/localhost/.test(window.location.href)
submenus = _.without submenus, 'multiplayer' unless me.isAdmin() or (@level?.get('type') in ['ladder', 'hero-ladder', 'course-ladder'] and @level.get('slug') not in ['ace-of-coders', 'elemental-wars'])
@includedSubmenus = submenus

View file

@ -15,6 +15,7 @@ module.exports = class LevelGuideView extends CocoView
'click .start-subscription-button': 'clickSubscribe'
constructor: (options) ->
super options
@levelSlug = options.level.get('slug')
@sessionID = options.session.get('_id')
@requiresSubscription = not me.isPremium()
@ -39,10 +40,10 @@ module.exports = class LevelGuideView extends CocoView
@docs = specific.concat(general)
@docs = $.extend(true, [], @docs)
@docs = [@docs[0]] if @firstOnly and @docs[0]
@addPicoCTFProblem() if window.serverConfig.picoCTF
doc.html = marked(utils.filterMarkdownCodeLanguages(utils.i18n(doc, 'body'))) for doc in @docs
doc.slug = _.string.slugify(doc.name) for doc in @docs
doc.name = (utils.i18n doc, 'name') for doc in @docs
super options
destroy: ->
if @vimeoListenerAttached
@ -89,7 +90,7 @@ module.exports = class LevelGuideView extends CocoView
clickSubscribe: (e) ->
level = @levelSlug # Save ref to level slug
@openModalView new SubscribeModal()
# TODO: Added levelID on 2/9/16. Remove level property and associated AnalyticsLogEvent 'properties.level' index later.
# TODO: Added levelID on 2/9/16. Remove level property and associated AnalyticsLogEvent 'properties.level' index later.
window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'help video clicked', level: level, levelID: level
clickTab: (e) =>
@ -158,3 +159,17 @@ module.exports = class LevelGuideView extends CocoView
else
window.attachEvent('onmessage', @onMessageReceived, false)
@vimeoListenerAttached = true
addPicoCTFProblem: ->
return unless problem = @options.level.picoCTFProblem
@docs = [name: 'Intro', body: '', slug: 'intro'] unless @docs.length
for doc in @docs when doc.name in ['Overview', 'Intro']
doc.body += """
### #{problem.name}
#{problem.description}
#{problem.category} - #{problem.score} points
Hint: #{problem.hints}
""".replace /<p>(.*?)<\/p>/gi, '$1'