Start to rework CampaignView when we're in picoCTF mode

This commit is contained in:
Nick Winter 2016-02-16 20:39:59 -08:00
parent 0aa3418e44
commit fe351be32e
7 changed files with 64 additions and 20 deletions

View file

@ -76,6 +76,7 @@
<script>
// Placeholder for iPad, which inspects the user object at the bottom of an injected page.
window.serverConfig = "serverConfigTag";
window.userObject = "userObjectTag";
window.me = {
get: function(attribute) { return window.userObject[attribute]; }

View file

@ -14,6 +14,8 @@ module.exports = class CocoRouter extends Backbone.Router
routes:
'': ->
if window.serverConfig.picoCTF
return @routeDirectly 'play/CampaignView', ['picoctf'], {}
# Testing new home page
group = me.getHomepageGroup()
return @routeDirectly('HomeView', [], { withTeacherNote: true }) if group is 'home-with-note'
@ -147,6 +149,7 @@ module.exports = class CocoRouter extends Backbone.Router
@navigate e, {trigger: true}
routeDirectly: (path, args, options={}) ->
path = 'play/CampaignView' if window.serverConfig.picoCTF and not /^(views\/)?play/.test(path)
path = "views/#{path}" if not _.string.startsWith(path, 'views/')
ViewClass = @tryToLoadModule path
if not ViewClass and application.moduleLoader.load(path)

View file

@ -49,6 +49,7 @@ Application = initialize: ->
@isProduction = -> document.location.href.search('https?://localhost:3000') is -1
@isIPadApp = webkit?.messageHandlers? and navigator.userAgent?.indexOf('CodeCombat-iPad') isnt -1
$('body').addClass 'ipad' if @isIPadApp
$('body').addClass 'picoctf' if window.serverConfig.picoCTF
if $.browser.msie and parseInt($.browser.version) is 10
$("html").addClass("ie10")
@tracker = new Tracker()

View file

@ -414,4 +414,10 @@ body > iframe[src^="https://apis.google.com"]
border: 2px solid #350f0d
background: #e6251c
color: white
padding: 0.0em 0.6em 0.1em
padding: 0.0em 0.6em 0.1em
body.picoctf .picoctf-hide
display: none
body:not(.picoctf) .picoctf-show
display: none

View file

@ -611,13 +611,23 @@ $gameControlMargin: 30px
margin: 15px 0
min-width: 100px
#small-nav-logo
.small-nav-logo, .picoctf-powered-by
position: absolute
top: 1%
left: 1%
height: 60px
z-index: 1
.picoctf-logo .small-nav-logo
height: 30px
.picoctf-powered-by
color: rgb(227, 173, 53)
top: calc(1% + 30px)
img
height: 30px
body.ipad #campaign-view
// iPad only supports up to Kithgard Gates for now.
.campaign-switch
@ -625,3 +635,4 @@ body.ipad #campaign-view
body[lang='ru'] .portals h2
font-size: 26px

View file

@ -1,5 +1,12 @@
a(href="/")
img#small-nav-logo(src="/images/pages/base/logo.png", title="CodeCombat - Learn how to code by playing a game", alt="CodeCombat")
a(href="/").picoctf-hide
img.small-nav-logo(src="/images/pages/base/logo.png", title="CodeCombat - Learn how to code by playing a game", alt="CodeCombat")
.picoctf-show
a(href="http://staging.picoctf.com").picoctf-logo
img.small-nav-logo(src="http://picoctf.com/img/2014_logo_blue2.svg", title="picoCTF home", alt="picoCTF home")
a(href="http://codecombat.com").picoctf-powered-by
em.spr powered by
img(src="/images/pages/base/logo.png", title="Powered by CodeCombat - Learn how to code by playing a game ", alt="Powered by CodeCombat")
if campaign
.map
@ -36,7 +43,7 @@ if campaign
.level-status
h3= i18n(level, 'name') + (level.disabled ? " (Coming soon!)" : (level.locked ? " (Locked)" : ""))
- var description = i18n(level, 'description') || level.description || ""
.level-description!= marked(description)
.level-description!= marked(description, {sanitize: !picoCTF})
if level.disabled
p
span.spr(data-i18n="play.awaiting_levels_adventurer_prefix") We release five levels per week.
@ -99,7 +106,7 @@ else
p.campaign-description
span= i18n(campaign.attributes, 'description')
.game-controls.header-font
.game-controls.header-font.picoctf-hide
button.btn.poll.hidden(data-i18n="[title]play.poll")
a.btn.clans(href="/clans", data-i18n="[title]clans.clans")
button.btn.items(data-toggle='coco-modal', data-target='play/modal/PlayItemsModal', data-i18n="[title]play.items")
@ -114,7 +121,7 @@ else
if me.get('anonymous', true)
button.btn.settings(data-toggle='coco-modal', data-target='core/AuthModal', data-i18n="[title]play.settings")
.user-status.header-font
.user-status.header-font.picoctf-hide
.user-status-line
span.gem.gem-30
span#gems-count.spr= me.gems()
@ -137,7 +144,7 @@ button.btn.btn-lg.btn-inverse.campaign-control-button#volume-button(data-i18n="[
.glyphicon.glyphicon-volume-up
if campaign && !editorMode
button.btn.btn-lg.btn-inverse.campaign-control-button#back-button(data-i18n="[title]resources.campaigns", title="Campaigns")
button.btn.btn-lg.btn-inverse.campaign-control-button.picoctf-hide#back-button(data-i18n="[title]resources.campaigns", title="Campaigns")
.glyphicon.glyphicon-globe
if editorMode

View file

@ -63,18 +63,22 @@ module.exports = class CampaignView extends RootView
constructor: (options, @terrain) ->
super options
@terrain = 'picoctf' if window.serverConfig.picoCTF
@editorMode = options?.editorMode
if @editorMode
@terrain ?= 'dungeon'
@levelStatusMap = {}
@levelPlayCountMap = {}
@levelDifficultyMap = {}
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
@listenToOnce @sessions, 'sync', @onSessionsLoaded
unless @terrain
@campaigns = @supermodel.loadCollection(new CampaignsCollection(), 'campaigns', null, 1).model
@listenToOnce @campaigns, 'sync', @onCampaignsLoaded
return
if window.serverConfig.picoCTF
@supermodel.addRequestResource(url: '/picoctf/problems', success: @onPicoCTFProblemsLoaded).load()
else
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
@listenToOnce @sessions, 'sync', @onSessionsLoaded
unless @terrain
@campaigns = @supermodel.loadCollection(new CampaignsCollection(), 'campaigns', null, 1).model
@listenToOnce @campaigns, 'sync', @onCampaignsLoaded
return
@campaign = new Campaign({_id:@terrain})
@campaign.saveBackups = @editorMode
@ -187,6 +191,7 @@ module.exports = class CampaignView extends RootView
context.levelDifficultyMap = @levelDifficultyMap
context.levelPlayCountMap = @levelPlayCountMap
context.isIPadApp = application.isIPadApp
context.picoCTF = window.serverConfig.picoCTF
context.requiresSubscription = @requiresSubscription
context.editorMode = @editorMode
context.adjacentCampaigns = _.filter _.values(_.cloneDeep(@campaign?.get('adjacentCampaigns') or {})), (ac) =>
@ -267,10 +272,18 @@ module.exports = class CampaignView extends RootView
level.locked = true if level.slug is 'kithgard-mastery' and @calculateExperienceScore() is 0
level.locked = false if @levelStatusMap[level.slug] in ['started', 'complete']
level.locked = false if @editorMode
level.locked = false if @campaign?.get('name') is 'Auditions'
level.locked = false if @campaign?.get('name') is 'Intro'
level.locked = false if @campaign?.get('name') in ['Auditions', 'Intro']
level.locked = false if me.isInGodMode()
#level.locked = false if level.slug is 'robot-ragnarok'
if window.serverConfig.picoCTF
if problem = _.find(@picoCTFProblems or [], pid: level.picoCTFProblem)
level.locked = false if problem.unlocked
level.description = """
### #{problem.name}
#{problem.description}
#{problem.category} - #{problem.score} points
""" # Skipping #{problem.hints}
level.disabled = true if level.adminOnly and @levelStatusMap[level.slug] not in ['started', 'complete']
level.disabled = false if me.isInGodMode()
level.color = 'rgb(255, 80, 60)'
@ -338,7 +351,7 @@ module.exports = class CampaignView extends RootView
adultPoint = me.get('ageRange') in ['18-24', '25-34', '35-44', '45-100'] # They have to have answered the poll for this, likely after Shadow Guard.
speedPoints = 0
for [levelSlug, speedThreshold] in [['dungeons-of-kithgard', 50], ['gems-in-the-deep', 55], ['shadow-guard', 55], ['forgetful-gemsmith', 40], ['true-names', 40]]
if _.find(@sessions.models, (session) -> session.get('levelID') is levelSlug)?.attributes.playtime <= speedThreshold
if _.find(@sessions?.models, (session) -> session.get('levelID') is levelSlug)?.attributes.playtime <= speedThreshold
++speedPoints
experienceScore = adultPoint + speedPoints # 0-6 score of how likely we think they are to be experienced and ready for Kithgard Mastery
return experienceScore
@ -421,11 +434,13 @@ module.exports = class CampaignView extends RootView
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
@levelDifficultyMap[session.get('levelID')] = session.get('state').difficulty if session.get('state')?.difficulty
@render()
@loadUserPollsRecord() unless me.get 'anonymous'
@loadUserPollsRecord() unless me.get('anonymous') or window.serverConfig.picoCTF
onCampaignsLoaded: (e) ->
@render()
onPicoCTFProblemsLoaded: (@picoCTFProblems) =>
preloadLevel: (levelSlug) ->
levelURL = "/db/level/#{levelSlug}"
level = new Level().setURL levelURL
@ -447,7 +462,7 @@ module.exports = class CampaignView extends RootView
onClickMap: (e) ->
@$levelInfo?.hide()
if @sessions.models.length < 3
if @sessions?.models.length < 3
# Restore the next level higlight for very new players who might otherwise get lost.
@highlightElement '.level.next', delay: 500, duration: 60000, rotation: 0, sides: ['top']
@ -482,7 +497,7 @@ module.exports = class CampaignView extends RootView
canPlayAnyway = not @requiresSubscription or level.adventurer or @levelStatusMap[level.slug]
if requiresSubscription and not canPlayAnyway
@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: 'map level clicked', level: levelSlug, levelID: levelSlug
else
@startLevel levelElement