mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-26 14:03:28 -04:00
Ads for free campaign players
Display leaderboard ads on campaign and play views. Do no show ads in classroom, picoCTF, or to teachers. Add no ads blurb to subscription features matrix. Scale game UI for ads on short screens. Closes #3491
This commit is contained in:
parent
1bab6cee88
commit
255ebbc048
12 changed files with 292 additions and 204 deletions
app
lib/surface
locale
models
styles
templates
views/play
|
@ -530,11 +530,20 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
newWidth = 0.55 * pageWidth
|
||||
newHeight = newWidth / aspectRatio
|
||||
return unless newWidth > 0 and newHeight > 0
|
||||
return if newWidth is oldWidth and newHeight is oldHeight and not @options.spectateGame
|
||||
return if newWidth < 200 or newHeight < 200
|
||||
|
||||
#scaleFactor = if application.isIPadApp then 2 else 1 # Retina
|
||||
scaleFactor = 1
|
||||
@normalCanvas.add(@webGLCanvas).attr width: newWidth * scaleFactor, height: newHeight * scaleFactor
|
||||
if @options.stayVisible
|
||||
availableHeight = window.innerHeight
|
||||
availableHeight -= $('.ad-container').outerHeight()
|
||||
availableHeight -= $('#game-area').outerHeight() - $('#canvas-wrapper').outerHeight()
|
||||
scaleFactor = availableHeight / newHeight if availableHeight < newHeight
|
||||
newWidth *= scaleFactor
|
||||
newHeight *= scaleFactor
|
||||
|
||||
return if newWidth is oldWidth and newHeight is oldHeight and not @options.spectateGame
|
||||
return if newWidth < 200 or newHeight < 200
|
||||
@normalCanvas.add(@webGLCanvas).attr width: newWidth, height: newHeight
|
||||
|
||||
# Cannot do this to the webGLStage because it does not use scaleX/Y.
|
||||
# Instead the LayerAdapter scales webGL-enabled layers.
|
||||
|
|
|
@ -502,6 +502,7 @@
|
|||
feature5: "Video tutorials"
|
||||
feature6: "Premium email support"
|
||||
feature7: "Private <strong>Clans</strong>"
|
||||
feature8: "<strong>No ads!</strong>"
|
||||
free: "Free"
|
||||
month: "month"
|
||||
must_be_logged: "You must be logged in first. Please create an account or log in from the menu above."
|
||||
|
|
|
@ -77,7 +77,7 @@ module.exports = class User extends CocoModel
|
|||
|
||||
# y = a * ln(1/b * (x + c)) + 1
|
||||
@levelFromExp: (xp) ->
|
||||
if xp > 0 then Math.floor(a * Math.log((1/b) * (xp + c))) + 1 else 1
|
||||
if xp > 0 then Math.floor(a * Math.log((1 / b) * (xp + c))) + 1 else 1
|
||||
|
||||
# x = b * e^((y-1)/a) - c
|
||||
@expForLevel: (level) ->
|
||||
|
@ -137,6 +137,16 @@ module.exports = class User extends CocoModel
|
|||
application.tracker.identify announcesActionAudioGroup: @announcesActionAudioGroup unless me.isAdmin()
|
||||
@announcesActionAudioGroup
|
||||
|
||||
getCampaignAdsGroup: ->
|
||||
return @campaignAdsGroup if @campaignAdsGroup
|
||||
group = me.get('testGroupNumber') % 2
|
||||
@campaignAdsGroup = switch group
|
||||
when 0 then 'no-ads'
|
||||
when 1 then 'leaderboard-ads'
|
||||
@campaignAdsGroup = 'no-ads' if me.isAdmin()
|
||||
application.tracker.identify campaignAdsGroup: @campaignAdsGroup unless me.isAdmin()
|
||||
@campaignAdsGroup
|
||||
|
||||
getHomepageGroup: ->
|
||||
# Only testing on en-US so localization issues are not a factor
|
||||
return 'new-home-student' unless _.string.startsWith(me.get('preferredLanguage', true) or 'en-US', 'en')
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
text-align: center
|
||||
tr
|
||||
td
|
||||
padding: 3px
|
||||
padding: 2px
|
||||
border-width: 0px
|
||||
border-top-width: 1px
|
||||
border-color: rgba(85, 85, 85, 0.1)
|
||||
|
|
|
@ -628,6 +628,14 @@ $gameControlMargin: 30px
|
|||
img
|
||||
height: 30px
|
||||
|
||||
.ad-container
|
||||
width: 100%
|
||||
height: 90px
|
||||
text-align: center
|
||||
|
||||
.gameplay-container
|
||||
position: absolute
|
||||
|
||||
body.ipad #campaign-view
|
||||
// iPad only supports up to Kithgard Gates for now.
|
||||
.campaign-switch
|
||||
|
|
|
@ -66,6 +66,7 @@ $level-resize-transition-time: 0.5s
|
|||
|
||||
.level-content
|
||||
position: relative
|
||||
background-color: black
|
||||
|
||||
#canvas-wrapper
|
||||
top: 50px
|
||||
|
@ -83,14 +84,14 @@ $level-resize-transition-time: 0.5s
|
|||
canvas#webgl-surface
|
||||
background-color: #333
|
||||
z-index: 1
|
||||
|
||||
|
||||
canvas#normal-surface
|
||||
z-index: 1
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
pointer-events: none
|
||||
|
||||
|
||||
canvas#webgl-surface, canvas#normal-surface
|
||||
display: block
|
||||
z-index: 2
|
||||
|
@ -259,6 +260,10 @@ $level-resize-transition-time: 0.5s
|
|||
right: 15px
|
||||
font-size: 30px
|
||||
|
||||
.ad-container
|
||||
width: 100%
|
||||
height: 90px
|
||||
text-align: center
|
||||
|
||||
html.fullscreen-editor
|
||||
#level-view
|
||||
|
|
|
@ -68,18 +68,26 @@
|
|||
span.glyphicon.glyphicon-ok
|
||||
tr
|
||||
td.feature-description
|
||||
span(data-i18n="subscribe.feature6")
|
||||
span(data-i18n="[html]subscribe.feature7")
|
||||
if !me.isOnPremiumServer()
|
||||
td.free-cell
|
||||
td.center-ok
|
||||
span.glyphicon.glyphicon-ok
|
||||
tr
|
||||
td.feature-description
|
||||
span(data-i18n="[html]subscribe.feature7")
|
||||
span(data-i18n="subscribe.feature6")
|
||||
if !me.isOnPremiumServer()
|
||||
td.free-cell
|
||||
td.center-ok
|
||||
span.glyphicon.glyphicon-ok
|
||||
if me.getCampaignAdsGroup() === 'leaderboard-ads'
|
||||
tr
|
||||
td.feature-description
|
||||
span(data-i18n="[html]subscribe.feature8")
|
||||
if !me.isOnPremiumServer()
|
||||
td.free-cell
|
||||
td.center-ok
|
||||
span.glyphicon.glyphicon-ok
|
||||
#parents-info(data-i18n="subscribe.parents")
|
||||
#payment-methods-info(data-i18n="subscribe.payment_methods")
|
||||
|
||||
|
|
|
@ -1,165 +1,182 @@
|
|||
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
|
||||
.gradient.horizontal-gradient.top-gradient
|
||||
.gradient.vertical-gradient.right-gradient
|
||||
.gradient.horizontal-gradient.bottom-gradient
|
||||
.gradient.vertical-gradient.left-gradient
|
||||
.map-background(alt="", draggable="false")
|
||||
|
||||
each level in levels
|
||||
if !level.hidden
|
||||
div(style="left: #{level.position.x}%; bottom: #{level.position.y}%; background-color: #{level.color}", class="level" + (level.next ? " next" : "") + (level.disabled ? " disabled" : "") + (level.locked ? " locked" : "") + " " + (levelStatusMap[level.slug] || ""), data-level-slug=level.slug, data-level-original=level.original, title=i18n(level, 'name') + (level.disabled ? ' (Coming Soon to Adventurers)' : ''))
|
||||
if level.unlocksHero && (!level.purchasedHero || editorMode)
|
||||
img.hero-portrait(src="/file/db/thang.type/#{level.unlocksHero}/portrait.png")
|
||||
a(href=level.type == 'hero' ? '#' : level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.slug}", disabled=level.disabled, data-level-slug=level.slug, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||
if level.slug == 'lost-viking'
|
||||
img.star(src="/file/db/thang.type/5441c3144e9aeb727cc97111/portrait.png")
|
||||
else if level.requiresSubscription
|
||||
img.star(src="/images/pages/play/star.png")
|
||||
if levelStatusMap[level.slug] === 'complete'
|
||||
img.banner(src="/images/pages/play/level-banner-complete.png")
|
||||
if levelStatusMap[level.slug] === 'started'
|
||||
img.banner(src="/images/pages/play/level-banner-started.png")
|
||||
if levelDifficultyMap[level.slug]
|
||||
.level-difficulty-banner-text= levelDifficultyMap[level.slug]
|
||||
div(style="left: #{level.position.x}%; bottom: #{level.position.y}%", class="level-shadow" + (level.next ? " next" : "") + " " + (levelStatusMap[level.slug] || ""))
|
||||
.level-info-container(data-level-slug=level.slug, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||
- var playCount = levelPlayCountMap[level.slug]
|
||||
.progress.progress-striped.active.hide
|
||||
.progress-bar(style="width: 100%")
|
||||
- var showsLeaderboard = levelStatusMap[level.slug] === 'complete' && ((level.scoreTypes && level.scoreTypes.length) || ['hero-ladder', 'course-ladder'].indexOf(level.type) !== -1);
|
||||
|
||||
div(class="level-info " + (levelStatusMap[level.slug] || "") + (level.requiresSubscription ? " premium" : "") + (showsLeaderboard ? " shows-leaderboard" : ""))
|
||||
.level-status
|
||||
h3= i18n(level, 'name') + (level.disabled ? " (Coming soon!)" : (level.locked ? " (Locked)" : ""))
|
||||
- var description = i18n(level, 'description') || level.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.
|
||||
a.spr(href="/contribute/adventurer")
|
||||
strong(data-i18n="play.awaiting_levels_adventurer") Sign up as an Adventurer
|
||||
span.spl(data-i18n="play.awaiting_levels_adventurer_suffix") to be the first to play new levels.
|
||||
if level.displayConcepts && level.displayConcepts.length
|
||||
p
|
||||
for concept in level.displayConcepts
|
||||
kbd(data-i18n="concepts." + concept)
|
||||
|
||||
if !level.disabled && !level.locked
|
||||
if playCount && playCount.sessions
|
||||
.play-counts.hidden
|
||||
span.spl.spr= playCount.sessions
|
||||
span(data-i18n="play.players") players
|
||||
span.spr , #{Math.round(playCount.playtime / 3600)}
|
||||
span(data-i18n="play.hours_played") hours played
|
||||
if showsLeaderboard
|
||||
button.btn.btn-warning.btn.btn-lg.btn-illustrated.view-solutions(data-level-slug=level.slug)
|
||||
span(data-i18n="leaderboard.scores")
|
||||
button.btn.btn-success.btn.btn-lg.btn-illustrated.start-level(data-i18n="common.play") Play
|
||||
if me.get('courseInstances') && me.get('courseInstances').length
|
||||
.course-version.hidden(data-level-original=level.original)
|
||||
em(data-i18n="general.or")
|
||||
| ...
|
||||
br
|
||||
button.btn.btn-primary.btn.btn-lg.btn-illustrated
|
||||
span(data-i18n="play.play_classroom_version") Play Classroom Version
|
||||
else if level.unlocksHero && !level.purchasedHero
|
||||
img.hero-portrait(src="/file/db/thang.type/#{level.unlocksHero}/portrait.png", style="left: #{level.position.x}%; bottom: #{level.position.y}%;")
|
||||
|
||||
for adjacentCampaign in adjacentCampaigns
|
||||
a(href=(editorMode ? "/editor/campaign/" : "/play/") + adjacentCampaign.slug)
|
||||
span.glyphicon.glyphicon-share-alt.campaign-switch(style=adjacentCampaign.style, title=adjacentCampaign.name, data-campaign-id=adjacentCampaign.id)
|
||||
|
||||
else
|
||||
.portal
|
||||
.portals
|
||||
for campaignSlug in ['dungeon', 'forest', 'desert', 'mountain', 'glacier', 'volcano']
|
||||
- var campaign = campaigns[campaignSlug];
|
||||
- var godmode = me.get('permissions', true).indexOf('godmode') != -1;
|
||||
div(class="campaign #{campaignSlug}" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
|
||||
.campaign-label
|
||||
h2.campaign-name
|
||||
if campaign
|
||||
span= i18n(campaign.attributes, 'fullName')
|
||||
else
|
||||
span ???
|
||||
if campaign && campaign.levelsTotal
|
||||
h3.levels-completed
|
||||
span= campaign.levelsCompleted
|
||||
| /
|
||||
span= campaign.levelsTotal
|
||||
if campaign && campaign.locked && !godmode
|
||||
h3.campaign-locked(data-i18n="play.locked") Locked
|
||||
else if campaign
|
||||
btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button
|
||||
if campaign && campaign.get('description')
|
||||
p.campaign-description
|
||||
span= i18n(campaign.attributes, 'description')
|
||||
|
||||
.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")
|
||||
button.btn.heroes(data-toggle='coco-modal', data-target='play/modal/PlayHeroesModal', data-i18n="[title]play.heroes")
|
||||
button.btn.achievements(data-toggle='coco-modal', data-target='play/modal/PlayAchievementsModal', data-i18n="[title]play.achievements")
|
||||
if me.get('anonymous') === false || me.get('iosIdentifierForVendor') || isIPadApp
|
||||
button.btn.gems(data-toggle='coco-modal', data-target='play/modal/BuyGemsModal', data-i18n="[title]play.buy_gems")
|
||||
if !me.get('anonymous', true)
|
||||
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
|
||||
//if me.isAdmin()
|
||||
// button.btn.settings(data-toggle='coco-modal', data-target='play/modal/PlaySettingsModal', data-i18n="[title]play.settings")
|
||||
if me.get('anonymous', true)
|
||||
button.btn.settings(data-toggle='coco-modal', data-target='core/CreateAccountModal', data-i18n="[title]play.settings")
|
||||
|
||||
.user-status.header-font.picoctf-hide
|
||||
.user-status-line
|
||||
span.gem.gem-30
|
||||
span#gems-count.spr= me.gems()
|
||||
span.level-indicator(data-i18n="general.player_level")
|
||||
span.player-level.spr= me.level()
|
||||
span.player-hero-icon
|
||||
if me.get('anonymous')
|
||||
span.player-name.spr(data-i18n="play.anonymous") Anonymous Player
|
||||
button.btn.btn-illustrated.login-button.btn-warning(data-i18n="login.log_in")
|
||||
button.btn.btn-illustrated.signup-button.btn-danger(data-i18n="signup.sign_up")
|
||||
if view.showAds()
|
||||
// TODO: loading this multiple times yields script error:
|
||||
// Uncaught TagError: adsbygoogle.push() error: All ins elements in the DOM with class=adsbygoogle already have ads in them.
|
||||
.ad-container
|
||||
if campaign
|
||||
script(async, src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js")
|
||||
ins.adsbygoogle(style="display:inline-block;width:728px;height:90px", data-ad-client="ca-pub-6640930638193614", data-ad-slot="4924994487")
|
||||
script.
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
else
|
||||
a(data-toggle="coco-modal", data-target="play/modal/PlayAccountModal").player-name.spr= me.get('name')
|
||||
button#logout-button.btn.btn-illustrated.btn-warning(data-i18n="login.log_out") Log Out
|
||||
if me.isPremium()
|
||||
button.btn.btn-illustrated.btn-primary(data-i18n="nav.contact", data-toggle="coco-modal", data-target="core/ContactModal") Contact
|
||||
script(async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js")
|
||||
ins.adsbygoogle(style="display:inline-block;width:728px;height:90px", data-ad-client="ca-pub-6640930638193614", data-ad-slot="4469166082")
|
||||
script.
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
|
||||
button.btn.btn-lg.btn-inverse.campaign-control-button.picoctf-hide#volume-button(data-i18n="[title]play.adjust_volume", title="Adjust volume")
|
||||
.glyphicon.glyphicon-volume-off
|
||||
.glyphicon.glyphicon-volume-down
|
||||
.glyphicon.glyphicon-volume-up
|
||||
// TODO: .gameplay-container causes world map buttons to briefly appear in top left of screen
|
||||
.gameplay-container
|
||||
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")
|
||||
|
||||
if campaign && !editorMode
|
||||
button.btn.btn-lg.btn-inverse.campaign-control-button.picoctf-hide#back-button(data-i18n="[title]resources.campaigns", title="Campaigns")
|
||||
.glyphicon.glyphicon-globe
|
||||
.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 editorMode
|
||||
button.btn.btn-lg.btn-inverse.campaign-control-button#clear-storage-button(data-i18n="[title]editor.clear_storage", title="Clear your local changes")
|
||||
.glyphicon.glyphicon-refresh
|
||||
if campaign
|
||||
.map
|
||||
.gradient.horizontal-gradient.top-gradient
|
||||
.gradient.vertical-gradient.right-gradient
|
||||
.gradient.horizontal-gradient.bottom-gradient
|
||||
.gradient.vertical-gradient.left-gradient
|
||||
.map-background(alt="", draggable="false")
|
||||
|
||||
if campaign && campaign.loaded
|
||||
h1#campaign-status.picoctf-hide
|
||||
.campaign-status-background
|
||||
.campaign-name
|
||||
- var fullName = i18n(campaign.attributes, 'fullName')
|
||||
if (me.get('preferredLanguage', true) || 'en-US').split('-')[0] == 'en' || fullName != campaign.get('fullName')
|
||||
// We have a translation.
|
||||
span= fullName
|
||||
.levels-completed
|
||||
span= levelsCompleted
|
||||
| /
|
||||
span= levelsTotal
|
||||
each level in levels
|
||||
if !level.hidden
|
||||
div(style="left: #{level.position.x}%; bottom: #{level.position.y}%; background-color: #{level.color}", class="level" + (level.next ? " next" : "") + (level.disabled ? " disabled" : "") + (level.locked ? " locked" : "") + " " + (levelStatusMap[level.slug] || ""), data-level-slug=level.slug, data-level-original=level.original, title=i18n(level, 'name') + (level.disabled ? ' (Coming Soon to Adventurers)' : ''))
|
||||
if level.unlocksHero && (!level.purchasedHero || editorMode)
|
||||
img.hero-portrait(src="/file/db/thang.type/#{level.unlocksHero}/portrait.png")
|
||||
a(href=level.type == 'hero' ? '#' : level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.slug}", disabled=level.disabled, data-level-slug=level.slug, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||
if level.slug == 'lost-viking'
|
||||
img.star(src="/file/db/thang.type/5441c3144e9aeb727cc97111/portrait.png")
|
||||
else if level.requiresSubscription
|
||||
img.star(src="/images/pages/play/star.png")
|
||||
if levelStatusMap[level.slug] === 'complete'
|
||||
img.banner(src="/images/pages/play/level-banner-complete.png")
|
||||
if levelStatusMap[level.slug] === 'started'
|
||||
img.banner(src="/images/pages/play/level-banner-started.png")
|
||||
if levelDifficultyMap[level.slug]
|
||||
.level-difficulty-banner-text= levelDifficultyMap[level.slug]
|
||||
div(style="left: #{level.position.x}%; bottom: #{level.position.y}%", class="level-shadow" + (level.next ? " next" : "") + " " + (levelStatusMap[level.slug] || ""))
|
||||
.level-info-container(data-level-slug=level.slug, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||
- var playCount = levelPlayCountMap[level.slug]
|
||||
.progress.progress-striped.active.hide
|
||||
.progress-bar(style="width: 100%")
|
||||
- var showsLeaderboard = levelStatusMap[level.slug] === 'complete' && ((level.scoreTypes && level.scoreTypes.length) || ['hero-ladder', 'course-ladder'].indexOf(level.type) !== -1);
|
||||
|
||||
div(class="level-info " + (levelStatusMap[level.slug] || "") + (level.requiresSubscription ? " premium" : "") + (showsLeaderboard ? " shows-leaderboard" : ""))
|
||||
.level-status
|
||||
h3= i18n(level, 'name') + (level.disabled ? " (Coming soon!)" : (level.locked ? " (Locked)" : ""))
|
||||
- var description = i18n(level, 'description') || level.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.
|
||||
a.spr(href="/contribute/adventurer")
|
||||
strong(data-i18n="play.awaiting_levels_adventurer") Sign up as an Adventurer
|
||||
span.spl(data-i18n="play.awaiting_levels_adventurer_suffix") to be the first to play new levels.
|
||||
if level.displayConcepts && level.displayConcepts.length
|
||||
p
|
||||
for concept in level.displayConcepts
|
||||
kbd(data-i18n="concepts." + concept)
|
||||
|
||||
if !level.disabled && !level.locked
|
||||
if playCount && playCount.sessions
|
||||
.play-counts.hidden
|
||||
span.spl.spr= playCount.sessions
|
||||
span(data-i18n="play.players") players
|
||||
span.spr , #{Math.round(playCount.playtime / 3600)}
|
||||
span(data-i18n="play.hours_played") hours played
|
||||
if showsLeaderboard
|
||||
button.btn.btn-warning.btn.btn-lg.btn-illustrated.view-solutions(data-level-slug=level.slug)
|
||||
span(data-i18n="leaderboard.scores")
|
||||
button.btn.btn-success.btn.btn-lg.btn-illustrated.start-level(data-i18n="common.play") Play
|
||||
if me.get('courseInstances') && me.get('courseInstances').length
|
||||
.course-version.hidden(data-level-original=level.original)
|
||||
em(data-i18n="general.or")
|
||||
| ...
|
||||
br
|
||||
button.btn.btn-primary.btn.btn-lg.btn-illustrated
|
||||
span(data-i18n="play.play_classroom_version") Play Classroom Version
|
||||
else if level.unlocksHero && !level.purchasedHero
|
||||
img.hero-portrait(src="/file/db/thang.type/#{level.unlocksHero}/portrait.png", style="left: #{level.position.x}%; bottom: #{level.position.y}%;")
|
||||
|
||||
for adjacentCampaign in adjacentCampaigns
|
||||
a(href=(editorMode ? "/editor/campaign/" : "/play/") + adjacentCampaign.slug)
|
||||
span.glyphicon.glyphicon-share-alt.campaign-switch(style=adjacentCampaign.style, title=adjacentCampaign.name, data-campaign-id=adjacentCampaign.id)
|
||||
|
||||
else
|
||||
.portal
|
||||
.portals
|
||||
for campaignSlug in ['dungeon', 'forest', 'desert', 'mountain', 'glacier', 'volcano']
|
||||
- var campaign = campaigns[campaignSlug];
|
||||
- var godmode = me.get('permissions', true).indexOf('godmode') != -1;
|
||||
div(class="campaign #{campaignSlug}" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
|
||||
.campaign-label
|
||||
h2.campaign-name
|
||||
if campaign
|
||||
span= i18n(campaign.attributes, 'fullName')
|
||||
else
|
||||
span ???
|
||||
if campaign && campaign.levelsTotal
|
||||
h3.levels-completed
|
||||
span= campaign.levelsCompleted
|
||||
| /
|
||||
span= campaign.levelsTotal
|
||||
if campaign && campaign.locked && !godmode
|
||||
h3.campaign-locked(data-i18n="play.locked") Locked
|
||||
else if campaign
|
||||
btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button
|
||||
if campaign && campaign.get('description')
|
||||
p.campaign-description
|
||||
span= i18n(campaign.attributes, 'description')
|
||||
|
||||
.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")
|
||||
button.btn.heroes(data-toggle='coco-modal', data-target='play/modal/PlayHeroesModal', data-i18n="[title]play.heroes")
|
||||
button.btn.achievements(data-toggle='coco-modal', data-target='play/modal/PlayAchievementsModal', data-i18n="[title]play.achievements")
|
||||
if me.get('anonymous') === false || me.get('iosIdentifierForVendor') || isIPadApp
|
||||
button.btn.gems(data-toggle='coco-modal', data-target='play/modal/BuyGemsModal', data-i18n="[title]play.buy_gems")
|
||||
if !me.get('anonymous', true)
|
||||
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
|
||||
//if me.isAdmin()
|
||||
// button.btn.settings(data-toggle='coco-modal', data-target='play/modal/PlaySettingsModal', data-i18n="[title]play.settings")
|
||||
if me.get('anonymous', true)
|
||||
button.btn.settings(data-toggle='coco-modal', data-target='core/CreateAccountModal', data-i18n="[title]play.settings")
|
||||
|
||||
.user-status.header-font.picoctf-hide
|
||||
.user-status-line
|
||||
span.gem.gem-30
|
||||
span#gems-count.spr= me.gems()
|
||||
span.level-indicator(data-i18n="general.player_level")
|
||||
span.player-level.spr= me.level()
|
||||
span.player-hero-icon
|
||||
if me.get('anonymous')
|
||||
span.player-name.spr(data-i18n="play.anonymous") Anonymous Player
|
||||
button.btn.btn-illustrated.login-button.btn-warning(data-i18n="login.log_in")
|
||||
button.btn.btn-illustrated.signup-button.btn-danger(data-i18n="signup.sign_up")
|
||||
else
|
||||
a(data-toggle="coco-modal", data-target="play/modal/PlayAccountModal").player-name.spr= me.get('name')
|
||||
button#logout-button.btn.btn-illustrated.btn-warning(data-i18n="login.log_out") Log Out
|
||||
if me.isPremium()
|
||||
button.btn.btn-illustrated.btn-primary(data-i18n="nav.contact", data-toggle="coco-modal", data-target="core/ContactModal") Contact
|
||||
|
||||
button.btn.btn-lg.btn-inverse.campaign-control-button.picoctf-hide#volume-button(data-i18n="[title]play.adjust_volume", title="Adjust volume")
|
||||
.glyphicon.glyphicon-volume-off
|
||||
.glyphicon.glyphicon-volume-down
|
||||
.glyphicon.glyphicon-volume-up
|
||||
|
||||
if campaign && !editorMode
|
||||
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
|
||||
button.btn.btn-lg.btn-inverse.campaign-control-button#clear-storage-button(data-i18n="[title]editor.clear_storage", title="Clear your local changes")
|
||||
.glyphicon.glyphicon-refresh
|
||||
|
||||
if campaign && campaign.loaded
|
||||
h1#campaign-status.picoctf-hide
|
||||
.campaign-status-background
|
||||
.campaign-name
|
||||
- var fullName = i18n(campaign.attributes, 'fullName')
|
||||
if (me.get('preferredLanguage', true) || 'en-US').split('-')[0] == 'en' || fullName != campaign.get('fullName')
|
||||
// We have a translation.
|
||||
span= fullName
|
||||
.levels-completed
|
||||
span= levelsCompleted
|
||||
| /
|
||||
span= levelsTotal
|
||||
|
|
|
@ -1,49 +1,59 @@
|
|||
#level-loading-view
|
||||
if view.showAds()
|
||||
// TODO: loading this multiple times yields script error:
|
||||
// Uncaught TagError: adsbygoogle.push() error: All ins elements in the DOM with class=adsbygoogle already have ads in them.
|
||||
.ad-container
|
||||
script(async, src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js")
|
||||
ins.adsbygoogle(style="display:inline-block;width:728px;height:90px", data-ad-client="ca-pub-6640930638193614", data-ad-slot="5527096883")
|
||||
script.
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
|
||||
.level-content
|
||||
#control-bar-view
|
||||
.game-container
|
||||
#level-loading-view
|
||||
|
||||
#fullscreen-editor-background-screen(title="Click to minimize the code editor")
|
||||
.level-content
|
||||
#control-bar-view
|
||||
|
||||
#code-area
|
||||
#code-area-gradient.gradient
|
||||
#tome-view
|
||||
#fullscreen-editor-background-screen(title="Click to minimize the code editor")
|
||||
|
||||
#game-area
|
||||
#code-area
|
||||
#code-area-gradient.gradient
|
||||
#tome-view
|
||||
|
||||
#canvas-wrapper
|
||||
canvas(width=924, height=589)#webgl-surface
|
||||
canvas(width=924, height=589)#normal-surface
|
||||
#ascii-surface
|
||||
#canvas-left-gradient.gradient
|
||||
#canvas-top-gradient.gradient
|
||||
#goals-view
|
||||
#game-area
|
||||
|
||||
#level-flags-view
|
||||
#canvas-wrapper
|
||||
canvas(width=924, height=589)#webgl-surface
|
||||
canvas(width=924, height=589)#normal-surface
|
||||
#ascii-surface
|
||||
#canvas-left-gradient.gradient
|
||||
#canvas-top-gradient.gradient
|
||||
#goals-view
|
||||
|
||||
#gold-view
|
||||
#level-flags-view
|
||||
|
||||
#problem-alert-view
|
||||
#gold-view
|
||||
|
||||
#level-chat-view
|
||||
#problem-alert-view
|
||||
|
||||
#multiplayer-status-view
|
||||
#level-chat-view
|
||||
|
||||
#duel-stats-view
|
||||
#multiplayer-status-view
|
||||
|
||||
#playback-view
|
||||
#duel-stats-view
|
||||
|
||||
#thang-hud
|
||||
#playback-view
|
||||
|
||||
#level-dialogue-view
|
||||
#thang-hud
|
||||
|
||||
button.btn.btn-lg.btn-warning.banner.header-font#stop-real-time-playback-button(title="Stop real-time playback", data-i18n="play_level.skip") Skip
|
||||
#level-dialogue-view
|
||||
|
||||
#level-footer-shadow
|
||||
#level-footer-background
|
||||
button.btn.btn-lg.btn-warning.banner.header-font#stop-real-time-playback-button(title="Stop real-time playback", data-i18n="play_level.skip") Skip
|
||||
|
||||
if !me.get('anonymous')
|
||||
#play-footer(class=me.isPremium() ? "premium" : "")
|
||||
p(class='footer-link-text').picoctf-hide
|
||||
a.contact-link(title='Send CodeCombat a message', tabindex=-1, data-i18n="nav.contact") Contact
|
||||
#level-footer-shadow
|
||||
#level-footer-background
|
||||
|
||||
if !me.get('anonymous')
|
||||
#play-footer(class=me.isPremium() ? "premium" : "")
|
||||
p(class='footer-link-text').picoctf-hide
|
||||
a.contact-link(title='Send CodeCombat a message', tabindex=-1, data-i18n="nav.contact") Contact
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
.product
|
||||
h4.subscription-gem-amount x{{gems}} / mo
|
||||
h3(data-i18n="account.subscription")
|
||||
if me.isPremium()
|
||||
if me.hasSubscription()
|
||||
button.disabled.start-subscription-button.btn.btn-lg.btn-illustrated.btn-success
|
||||
| ✓
|
||||
span(data-i18n="account.subscribed")
|
||||
|
|
|
@ -266,6 +266,11 @@ module.exports = class CampaignView extends RootView
|
|||
authModal.mode = 'signup'
|
||||
@openModalView authModal
|
||||
|
||||
showAds: ->
|
||||
if application.isProduction() && !me.isPremium() && !me.isTeacher() && !window.serverConfig.picoCTF
|
||||
return me.getCampaignAdsGroup() is 'leaderboard-ads'
|
||||
false
|
||||
|
||||
annotateLevel: (level) ->
|
||||
level.position ?= { x: 10, y: 10 }
|
||||
level.locked = not me.ownsLevel level.original
|
||||
|
@ -554,6 +559,7 @@ module.exports = class CampaignView extends RootView
|
|||
aspectRatio = mapWidth / mapHeight
|
||||
pageWidth = @$el.width()
|
||||
pageHeight = @$el.height()
|
||||
pageHeight -= adContainerHeight if adContainerHeight = $('.ad-container').outerHeight()
|
||||
widthRatio = pageWidth / mapWidth
|
||||
heightRatio = pageHeight / mapHeight
|
||||
# Make sure we can see the whole map, fading to background in one dimension.
|
||||
|
|
|
@ -148,6 +148,13 @@ module.exports = class PlayLevelView extends RootView
|
|||
application.tracker?.trackEvent 'Finished Level Load', category: 'Play Level', label: @levelID, level: @levelID, loadDuration: @loadDuration
|
||||
application.tracker?.trackTiming @loadDuration, 'Level Load Time', @levelID, @levelID
|
||||
|
||||
isCourseMode: -> @courseID and @courseInstanceID
|
||||
|
||||
showAds: ->
|
||||
if application.isProduction() && !me.isPremium() && !me.isTeacher() && !window.serverConfig.picoCTF && !@isCourseMode()
|
||||
return me.getCampaignAdsGroup() is 'leaderboard-ads'
|
||||
false
|
||||
|
||||
# CocoView overridden methods ###############################################
|
||||
|
||||
getRenderData: ->
|
||||
|
@ -326,7 +333,13 @@ module.exports = class PlayLevelView extends RootView
|
|||
initSurface: ->
|
||||
webGLSurface = $('canvas#webgl-surface', @$el)
|
||||
normalSurface = $('canvas#normal-surface', @$el)
|
||||
@surface = new Surface(@world, normalSurface, webGLSurface, thangTypes: @supermodel.getModels(ThangType), observing: @observing, playerNames: @findPlayerNames(), levelType: @level.get('type', true))
|
||||
surfaceOptions =
|
||||
thangTypes: @supermodel.getModels(ThangType)
|
||||
observing: @observing
|
||||
playerNames: @findPlayerNames()
|
||||
levelType: @level.get('type', true)
|
||||
stayVisible: @showAds()
|
||||
@surface = new Surface(@world, normalSurface, webGLSurface, surfaceOptions)
|
||||
worldBounds = @world.getBounds()
|
||||
bounds = [{x: worldBounds.left, y: worldBounds.top}, {x: worldBounds.right, y: worldBounds.bottom}]
|
||||
@surface.camera.setBounds(bounds)
|
||||
|
@ -499,7 +512,8 @@ module.exports = class PlayLevelView extends RootView
|
|||
break
|
||||
Backbone.Mediator.publish 'tome:cast-spell', {}
|
||||
|
||||
onWindowResize: (e) => @endHighlight()
|
||||
onWindowResize: (e) =>
|
||||
@endHighlight()
|
||||
|
||||
onDisableControls: (e) ->
|
||||
return if e.controls and not ('level' in e.controls)
|
||||
|
@ -535,7 +549,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
@endHighlight()
|
||||
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world}
|
||||
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 = CourseVictoryModal if @isCourseMode()
|
||||
ModalClass = PicoCTFVictoryModal if window.serverConfig.picoCTF
|
||||
victoryModal = new ModalClass(options)
|
||||
@openModalView(victoryModal)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue