mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Reimplemented next-level arrow highlighting. Campaign Editor now draws lines to show level unlock patterns. Removed more old WorldMapView stuff. Can now configure Hero Placeholder say cooldowns per-level.
This commit is contained in:
parent
22e1318970
commit
f691eb9a86
6 changed files with 58 additions and 606 deletions
|
@ -22,7 +22,8 @@ class CocoModel extends Backbone.Model
|
|||
@usesVersions = @schema()?.properties?.version?
|
||||
|
||||
backupKey: ->
|
||||
if @usesVersions then @id else @id + ':' + @attributes.__v # TODO: doesn't work because __v doesn't actually increment. #2061
|
||||
if @usesVersions then @id else @id # + ':' + @attributes.__v # TODO: doesn't work because __v doesn't actually increment. #2061
|
||||
# if fixed, RevertModal will also need the fix
|
||||
|
||||
setProjection: (project) ->
|
||||
return if project is @project
|
||||
|
|
|
@ -126,6 +126,7 @@ module.exports = class Level extends CocoModel
|
|||
else if placeholderConfig.voiceRange # Pull in voiceRange
|
||||
levelThangComponent.config ?= {}
|
||||
levelThangComponent.config.voiceRange = placeholderConfig.voiceRange
|
||||
levelThangComponent.config.cooldown = placeholderConfig.cooldown
|
||||
|
||||
if isHero
|
||||
if equips = _.find levelThang.components, {original: LevelComponent.EquipsID}
|
||||
|
|
|
@ -237,6 +237,28 @@ $gameControlMargin: 30px
|
|||
&:hover
|
||||
text-decoration: none
|
||||
|
||||
.next-level-line
|
||||
transform-origin: 0 100%
|
||||
height: 8px
|
||||
position: absolute
|
||||
|
||||
.line
|
||||
width: calc(100% - 12px - 10px)
|
||||
float: left
|
||||
margin-top: 2px
|
||||
margin-bottom: 2px
|
||||
height: 4px
|
||||
background: repeating-linear-gradient(-45deg, #AF9F7D, #DFC89C 5px, #F1EAC0 5px, #AF9F7D 10px)
|
||||
box-shadow: 0px 0px 4px black
|
||||
|
||||
.point
|
||||
width: 12px
|
||||
float: left
|
||||
margin-top: -4px
|
||||
border-top: 8px solid transparent
|
||||
border-bottom: 8px solid transparent
|
||||
border-left: 12px solid lighten(#F1EAC0, 10%)
|
||||
|
||||
.game-controls
|
||||
position: absolute
|
||||
right: 1%
|
||||
|
|
|
@ -1,495 +0,0 @@
|
|||
@import "app/styles/mixins"
|
||||
@import "app/styles/bootstrap/variables"
|
||||
|
||||
$mapHeight: 1536
|
||||
$forestMapWidth: 2500
|
||||
$dungeonMapWidth: 2350
|
||||
$desertMapWidth: 2350
|
||||
$desertMapSeaBackground: rgba(113, 186, 208, 1)
|
||||
$desertMapSeaBackgroundTransparent: rgba(113, 186, 208, 0)
|
||||
$forestMapSeaBackground: rgba(113, 186, 208, 1)
|
||||
$forestMapSeaBackgroundTransparent: rgba(113, 186, 208, 0)
|
||||
$dungeonMapCaveBackground: rgba(68, 54, 45, 1)
|
||||
$dungeonMapCaveBackgroundTransparent: rgba(68, 54, 45, 0)
|
||||
$levelDotWidth: 2%
|
||||
$levelDotHeight: $levelDotWidth * $forestMapWidth / $mapHeight
|
||||
$levelDotZ: $levelDotHeight * 0.25
|
||||
$levelDotHoverZ: $levelDotZ * 2
|
||||
$levelDotShadowWidth: 0.8 * $levelDotWidth
|
||||
$levelDotShadowHeight: 0.8 * $levelDotHeight
|
||||
$levelClickRadius: 40px
|
||||
$gameControlSize: 80px
|
||||
$gameControlMargin: 30px
|
||||
|
||||
+keyframes(levelStartedPulse)
|
||||
from
|
||||
@include box-shadow(0px 0px 4px #333)
|
||||
margin-bottom: -$levelDotHeight / 3 + $levelDotZ
|
||||
50%
|
||||
@include box-shadow(0px 0px 22px skyblue)
|
||||
margin-bottom: -$levelDotHeight / 3 + ($levelDotHoverZ + $levelDotZ) / 2
|
||||
to
|
||||
@include box-shadow(0px 0px 4px #333)
|
||||
margin-bottom: -$levelDotHeight / 3 + $levelDotZ
|
||||
|
||||
#world-map-view
|
||||
width: 100%
|
||||
height: 100%
|
||||
position: absolute
|
||||
|
||||
.gradient
|
||||
position: absolute
|
||||
z-index: 0
|
||||
|
||||
&.horizontal-gradient
|
||||
left: 0
|
||||
right: 0
|
||||
height: 3%
|
||||
|
||||
&.vertical-gradient
|
||||
top: 0
|
||||
bottom: 0
|
||||
width: 3%
|
||||
|
||||
&.top-gradient
|
||||
top: 0
|
||||
|
||||
&.right-gradient
|
||||
right: 0
|
||||
|
||||
&.bottom-gradient
|
||||
bottom: 0
|
||||
|
||||
&.left-gradient
|
||||
left: 0
|
||||
|
||||
&.desert
|
||||
background-color: $desertMapSeaBackground
|
||||
|
||||
.top-gradient
|
||||
background: linear-gradient(to bottom, $desertMapSeaBackground 0%, $desertMapSeaBackgroundTransparent 100%)
|
||||
|
||||
.right-gradient
|
||||
background: linear-gradient(to left, $desertMapSeaBackground 0%, $desertMapSeaBackgroundTransparent 100%)
|
||||
|
||||
.bottom-gradient
|
||||
background: linear-gradient(to top, $desertMapSeaBackground 0%, $desertMapSeaBackgroundTransparent 100%)
|
||||
|
||||
.left-gradient
|
||||
background: linear-gradient(to right, $desertMapSeaBackground 0%, $desertMapSeaBackgroundTransparent 100%)
|
||||
|
||||
&.forest
|
||||
background-color: $forestMapSeaBackground
|
||||
|
||||
.top-gradient
|
||||
background: linear-gradient(to bottom, $forestMapSeaBackground 0%, $forestMapSeaBackgroundTransparent 100%)
|
||||
|
||||
.right-gradient
|
||||
background: linear-gradient(to left, $forestMapSeaBackground 0%, $forestMapSeaBackgroundTransparent 100%)
|
||||
|
||||
.bottom-gradient
|
||||
background: linear-gradient(to top, $forestMapSeaBackground 0%, $forestMapSeaBackgroundTransparent 100%)
|
||||
|
||||
.left-gradient
|
||||
background: linear-gradient(to right, $forestMapSeaBackground 0%, $forestMapSeaBackgroundTransparent 100%)
|
||||
|
||||
&.dungeon
|
||||
background-color: $dungeonMapCaveBackground
|
||||
|
||||
.top-gradient
|
||||
background: linear-gradient(to bottom, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
|
||||
|
||||
.right-gradient
|
||||
background: linear-gradient(to left, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
|
||||
|
||||
.bottom-gradient
|
||||
background: linear-gradient(to top, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
|
||||
|
||||
.left-gradient
|
||||
background: linear-gradient(to right, $dungeonMapCaveBackground 0%, $dungeonMapCaveBackgroundTransparent 100%)
|
||||
|
||||
.map
|
||||
position: relative
|
||||
|
||||
.map-background
|
||||
width: 100%
|
||||
height: 100%
|
||||
background-size: 100%
|
||||
@include user-select(none)
|
||||
|
||||
&.map-dungeon
|
||||
background-image: url('/images/pages/play/map_dungeon_1920.jpg')
|
||||
@media screen and ( max-width: 1366px )
|
||||
background-image: url('/images/pages/play/map_dungeon_1366.jpg')
|
||||
|
||||
&.map-forest
|
||||
background-image: url('/images/pages/play/map_forest_1920.jpg')
|
||||
@media screen and ( max-width: 1366px )
|
||||
background-image: url('/images/pages/play/map_forest_1366.jpg')
|
||||
|
||||
&.map-desert
|
||||
background-image: url('/images/pages/play/map_desert_1920.jpg')
|
||||
@media screen and ( max-width: 1366px )
|
||||
background-image: url('/images/pages/play/map_desert_1366.jpg')
|
||||
|
||||
.level, .level-shadow
|
||||
position: absolute
|
||||
border-radius: 100%
|
||||
-webkit-transform: scaleY(0.75)
|
||||
transform: scaleY(0.75)
|
||||
|
||||
.level
|
||||
z-index: 2
|
||||
width: $levelDotWidth
|
||||
height: $levelDotHeight
|
||||
margin-left: -0.5 * $levelDotWidth
|
||||
margin-bottom: -$levelDotHeight / 3 + $levelDotZ
|
||||
border: 2px groove white
|
||||
@include transition(margin-bottom 0.5s ease)
|
||||
|
||||
&.disabled, &.locked
|
||||
background-image: url(/images/pages/game-menu/lock.png)
|
||||
background-size: 75%
|
||||
background-repeat: no-repeat
|
||||
background-position: 50% 50%
|
||||
opacity: 0.7
|
||||
|
||||
a
|
||||
cursor: default
|
||||
|
||||
&.next
|
||||
width: 2 * $levelDotWidth
|
||||
height: 2 * $levelDotHeight
|
||||
margin-left: -0.5 * 2 * $levelDotWidth
|
||||
margin-bottom: -2 * $levelDotHeight / 3 + 2 * $levelDotZ
|
||||
|
||||
&.started, &.next
|
||||
border: 3px solid lightgreen
|
||||
@include box-shadow(0px 0px 35px skyblue)
|
||||
|
||||
// Would be cool, but kills performance, since we have to re-render all the time.
|
||||
//&:not(:hover)
|
||||
// -webkit-animation-name: levelStartedPulse
|
||||
// -webkit-animation-duration: 3s
|
||||
// -webkit-animation-iteration-count: infinite
|
||||
|
||||
&.complete
|
||||
border: 3px solid gold
|
||||
@include box-shadow(0px 0px 35px skyblue)
|
||||
|
||||
img.banner
|
||||
position: absolute
|
||||
bottom: 38%
|
||||
left: -50%
|
||||
width: 200%
|
||||
pointer-events: none
|
||||
|
||||
img.star
|
||||
width: 100%
|
||||
bottom: 7%
|
||||
position: absolute
|
||||
pointer-events: none
|
||||
|
||||
.glyphicon-star
|
||||
position: absolute
|
||||
color: lightblue
|
||||
font-size: 21px
|
||||
left: 1.5px
|
||||
|
||||
&.started .glyphicon-star
|
||||
left: 0.5px
|
||||
|
||||
img.hero-portrait
|
||||
width: 120%
|
||||
position: absolute
|
||||
bottom: 75%
|
||||
left: 75%
|
||||
border: 1px solid black
|
||||
border-radius: 100%
|
||||
background: white
|
||||
|
||||
|
||||
.level-shadow
|
||||
z-index: 1
|
||||
width: $levelDotShadowWidth
|
||||
height: $levelDotShadowHeight
|
||||
margin-left: -0.5 * $levelDotShadowWidth
|
||||
margin-bottom: -$levelDotShadowHeight / 3
|
||||
background-color: black
|
||||
@include box-shadow(0px 0px 10px black)
|
||||
@include opacity(0.75)
|
||||
|
||||
&.next
|
||||
width: 2 * $levelDotShadowWidth
|
||||
height: 2 * $levelDotShadowHeight
|
||||
margin-left: -0.5 * 2 * $levelDotShadowWidth
|
||||
margin-bottom: -2 * $levelDotShadowHeight / 3
|
||||
|
||||
.level:hover
|
||||
// TODO: This rotate stops Firefox from flickering, but also disables the scaleY(0.75)
|
||||
// TODO: The dot looks like it's jumping.
|
||||
// TODO: -moz-transform: scaleY(0.75) didn't do anything
|
||||
// TODO: Does not break Chrome's oval.
|
||||
-moz-transform: rotate(0)
|
||||
margin-bottom: -$levelDotHeight / 3 + $levelDotHoverZ
|
||||
@include box-shadow(0px 0px 35px skyblue)
|
||||
|
||||
&.next
|
||||
margin-bottom: -2 * $levelDotHeight / 3 + 2 * $levelDotHoverZ
|
||||
|
||||
.level
|
||||
a
|
||||
display: block
|
||||
padding: $levelClickRadius
|
||||
margin-left: -0.5 * $levelClickRadius
|
||||
margin-top: -0.5 * $levelClickRadius
|
||||
border-radius: $levelClickRadius
|
||||
|
||||
&.next a
|
||||
padding: 2 * $levelClickRadius
|
||||
margin-left: 2 * -0.5 * $levelClickRadius
|
||||
margin-top: 2 * -0.5 * $levelClickRadius
|
||||
border-radius: 2 * $levelClickRadius
|
||||
|
||||
.tooltip
|
||||
z-index: 2
|
||||
|
||||
.level-info-container
|
||||
display: none
|
||||
position: absolute
|
||||
z-index: 3
|
||||
padding: 10px
|
||||
border-width: 16px 12px
|
||||
// Using modernizr-mixin for compat detection
|
||||
@include yep(borderimage)
|
||||
border-style: solid
|
||||
border-image: url(/images/level/popover_border_background.png) 16 12 fill round
|
||||
@include nope(borderimage)
|
||||
background-color: rgb(247, 242, 218)
|
||||
|
||||
.level-info.complete h3:after
|
||||
content: " - Complete!"
|
||||
color: green
|
||||
|
||||
.level-info.started h3:after
|
||||
content: " - Started"
|
||||
color: desaturate(green, 50%)
|
||||
|
||||
.level-info
|
||||
h3
|
||||
margin-top: 0
|
||||
margin-bottom: 0px
|
||||
|
||||
.level-description
|
||||
color: black
|
||||
text-shadow: 0 1px 0 white
|
||||
|
||||
.campaign-label
|
||||
text-shadow: 0 1px 0 white
|
||||
|
||||
.start-level
|
||||
display: block
|
||||
margin: 10px auto 0 auto
|
||||
width: 200px
|
||||
|
||||
.campaign-switch
|
||||
color: purple
|
||||
position: absolute
|
||||
z-index: 1
|
||||
font-size: 2vw
|
||||
text-shadow: 0 0 0.3vw white, 0 0 0.3vw white
|
||||
|
||||
&:hover
|
||||
text-decoration: none
|
||||
|
||||
&#desert-link
|
||||
left: 90%
|
||||
top: 18.5%
|
||||
transform: scaleY(-1.5) scaleX(1.5)
|
||||
|
||||
&#forest-back-link
|
||||
left: 2%
|
||||
top: 70.5%
|
||||
transform: rotate(216deg)
|
||||
|
||||
&#forest-link
|
||||
left: 94.5%
|
||||
top: 7%
|
||||
transform: rotate(-35deg)
|
||||
|
||||
&#dungeon-link
|
||||
left: 9%
|
||||
top: 54.5%
|
||||
transform: rotate(180deg)
|
||||
color: fuchsia
|
||||
|
||||
.game-controls
|
||||
position: absolute
|
||||
right: 1%
|
||||
bottom: 1%
|
||||
z-index: 3
|
||||
|
||||
.btn
|
||||
&:not(:first-child)
|
||||
margin-left: $gameControlMargin
|
||||
width: $gameControlSize
|
||||
height: $gameControlSize
|
||||
|
||||
background: url(/images/pages/play/menu_icons.png) no-repeat
|
||||
|
||||
position: relative
|
||||
img
|
||||
position: absolute
|
||||
left: 0
|
||||
top: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
background-size: cover
|
||||
@include transition(0.5s ease)
|
||||
@include box-shadow(2px 2px 4px black)
|
||||
border: 0
|
||||
border-radius: 12px
|
||||
// IE9 shows a blank white button with this MS gradient filter in place
|
||||
filter: none
|
||||
|
||||
&:hover
|
||||
@include box-shadow(0 0 12px #bbf)
|
||||
|
||||
&:active
|
||||
@include box-shadow(0 0 20px white)
|
||||
|
||||
&.heroes
|
||||
background-position: (-1 * $gameControlSize) 0px
|
||||
&.achievements
|
||||
background-position: (-2 * $gameControlSize) 0px
|
||||
&.account
|
||||
background-position: (-3 * $gameControlSize) 0px
|
||||
&.settings
|
||||
background-position: (-4 * $gameControlSize) 0px
|
||||
&.gems
|
||||
background-position: (-5 * $gameControlSize) 0px
|
||||
|
||||
.tooltip
|
||||
font-size: 24px
|
||||
|
||||
.tooltip-arrow
|
||||
display: none
|
||||
|
||||
.user-status
|
||||
position: absolute
|
||||
bottom: 16px
|
||||
left: 8px
|
||||
text-align: center
|
||||
font-size: 24px
|
||||
color: white
|
||||
text-shadow: 0px 2px 1px black, 0px -2px 1px black, -2px 0px 1px black, 2px 0px 1px black
|
||||
height: 32px
|
||||
line-height: 32px
|
||||
|
||||
.user-status-line
|
||||
position: relative
|
||||
|
||||
button.btn.btn-illustrated
|
||||
margin-left: 10px
|
||||
min-width: 90px
|
||||
height: 32px
|
||||
color: white
|
||||
|
||||
.gem, .player-level-icon, .player-hero-icon
|
||||
position: absolute
|
||||
top: 1px
|
||||
|
||||
#gems-count
|
||||
margin-left: 40px
|
||||
|
||||
.player-level
|
||||
margin-left: 34px
|
||||
|
||||
.player-name
|
||||
margin-left: 45px
|
||||
|
||||
$spriteSheetSize: 30px
|
||||
|
||||
.player-level-icon, .player-hero-icon
|
||||
background: transparent url(/images/pages/play/play-spritesheet.png)
|
||||
background-size: cover
|
||||
background-position: (-2 * $spriteSheetSize) 0
|
||||
display: inline-block
|
||||
width: 30px
|
||||
height: 30px
|
||||
margin: 0px 2px
|
||||
|
||||
.player-hero-icon
|
||||
margin-left: 10px
|
||||
background-position: (-4 * $spriteSheetSize) 0
|
||||
|
||||
&.knight
|
||||
background-position: (-5 * $spriteSheetSize) 0
|
||||
&.librarian
|
||||
background-position: (-6 * $spriteSheetSize) 0
|
||||
&.ninja
|
||||
background-position: (-7 * $spriteSheetSize) 0
|
||||
&.potion-master
|
||||
background-position: (-8 * $spriteSheetSize) 0
|
||||
&.samurai
|
||||
background-position: (-9 * $spriteSheetSize) 0
|
||||
&.trapper
|
||||
background-position: (-10 * $spriteSheetSize) 0
|
||||
&.forest-archer
|
||||
background-position: (-11 * $spriteSheetSize) 0
|
||||
&.sorcerer
|
||||
background-position: (-12 * $spriteSheetSize) 0
|
||||
|
||||
|
||||
#volume-button
|
||||
position: absolute
|
||||
left: 1%
|
||||
top: 1%
|
||||
padding: 3px 8px
|
||||
@include opacity(0.75)
|
||||
|
||||
&:hover
|
||||
@include opacity(1.0)
|
||||
|
||||
.glyphicon
|
||||
display: none
|
||||
font-size: 32px
|
||||
|
||||
&.vol-up .glyphicon.glyphicon-volume-up
|
||||
display: inline-block
|
||||
|
||||
&.vol-off .glyphicon.glyphicon-volume-off
|
||||
display: inline-block
|
||||
@include opacity(0.50)
|
||||
&:hover
|
||||
@include opacity(0.75)
|
||||
|
||||
&.vol-down .glyphicon.glyphicon-volume-down
|
||||
display: inline-block
|
||||
|
||||
#campaign-status
|
||||
position: absolute
|
||||
left: 0
|
||||
top: 15px
|
||||
width: 100%
|
||||
margin: 0
|
||||
text-align: center
|
||||
color: rgb(254,188,68)
|
||||
font-size: 30px
|
||||
text-shadow: black 2px 2px 0, black -2px -2px 0, black 2px -2px 0, black -2px 2px 0, black 2px 0px 0, black 0px -2px 0, black -2px 0px 0, black 0px 2px 0
|
||||
|
||||
|
||||
body:not(.ipad) #world-map-view
|
||||
.level-info-container
|
||||
pointer-events: none
|
||||
|
||||
|
||||
|
||||
body.ipad #world-map-view
|
||||
// iPad only supports up to Kithgard Gates for now.
|
||||
.campaign-switch
|
||||
display: none
|
||||
|
||||
.old-levels
|
||||
display: none
|
|
@ -1,106 +0,0 @@
|
|||
.map
|
||||
.gradient.horizontal-gradient.top-gradient
|
||||
.gradient.vertical-gradient.right-gradient
|
||||
.gradient.horizontal-gradient.bottom-gradient
|
||||
.gradient.vertical-gradient.left-gradient
|
||||
.map-background(class="map-"+mapType alt="", draggable="false")
|
||||
|
||||
- var seenNext = nextLevel;
|
||||
each level in campaign.levels
|
||||
if !level.hidden
|
||||
- var next = level.id == nextLevel || (!seenNext && levelStatusMap[level.id] != "complete" && !level.locked && !level.disabled && !editorMode);
|
||||
- seenNext = seenNext || next;
|
||||
div(style="left: #{level.x}%; bottom: #{level.y}%; background-color: #{level.color}", class="level" + (next ? " next" : "") + (level.disabled ? " disabled" : "") + (level.locked ? " locked" : "") + " " + levelStatusMap[level.id] || "", data-level-id=level.id, title=level.name + (level.disabled ? ' (Coming Soon to Adventurers)' : ''))
|
||||
if level.unlocksHero && !level.unlockedHero
|
||||
img.hero-portrait(src=level.unlocksHero.img)
|
||||
a(href=level.type == 'hero' ? '#' : level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.id}", disabled=level.disabled, data-level-id=level.id, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||
if level.requiresSubscription
|
||||
img.star(src="/images/pages/play/star.png")
|
||||
if levelStatusMap[level.id] === 'complete'
|
||||
img.banner(src="/images/pages/play/level-banner-complete.png")
|
||||
if levelStatusMap[level.id] === 'started'
|
||||
img.banner(src="/images/pages/play/level-banner-started.png")
|
||||
div(style="left: #{level.x}%; bottom: #{level.y}%", class="level-shadow" + (next ? " next" : "") + " " + levelStatusMap[level.id] || "")
|
||||
.level-info-container(data-level-id=level.id, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||
div(class="level-info " + (levelStatusMap[level.id] || ""))
|
||||
h3= level.name + (level.disabled ? " (Coming soon!)" : (level.locked ? " (Locked)" : ""))
|
||||
.level-description= level.description
|
||||
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.
|
||||
|
||||
- var playCount = levelPlayCountMap[level.id]
|
||||
if playCount && playCount.sessions > 20
|
||||
div
|
||||
span.spr #{playCount.sessions}
|
||||
span(data-i18n="play.players") players
|
||||
span.spr , #{Math.round(playCount.playtime / 3600)}
|
||||
span(data-i18n="play.hours_played") hours played
|
||||
.campaign-label(style="color: #{campaign.color}")= campaign.name
|
||||
if isIPadApp && !level.disabled && !level.locked
|
||||
button.btn.btn-success.btn-lg.start-level(data-i18n="common.play") Play
|
||||
if mapType === 'dungeon' && forestIsAvailable
|
||||
a#forest-link.glyphicon.glyphicon-share-alt.campaign-switch(href="/play/forest", data-i18n="[title]play.campaign_forest")
|
||||
if mapType === 'forest'
|
||||
a#dungeon-link.glyphicon.glyphicon-share-alt.campaign-switch(href="/play/dungeon", data-i18n="[title]play.campaign_dungeon")
|
||||
if desertIsAvailable
|
||||
a#desert-link.glyphicon.glyphicon-share-alt.campaign-switch(href="/play/desert", data-i18n="[title]play.campaign_desert")
|
||||
if mapType === 'desert'
|
||||
a#forest-back-link.glyphicon.glyphicon-share-alt.campaign-switch(href="/play/forest", data-i18n="[title]play.campaign_forest")
|
||||
|
||||
|
||||
.game-controls.header-font
|
||||
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.isAdmin()
|
||||
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
|
||||
button.btn.settings(data-toggle='coco-modal', data-target='play/modal/PlaySettingsModal', data-i18n="[title]play.settings")
|
||||
else if me.get('anonymous', true)
|
||||
button.btn.settings(data-toggle='coco-modal', data-target='core/AuthModal', data-i18n="[title]play.settings")
|
||||
// Don't show these things, they are bad and take us out of the game. Just wait until the new ones work.
|
||||
//else
|
||||
// a.btn.achievements(href="/user/#{me.getSlugOrID()}/stats", data-i18n="[title]play.achievements")
|
||||
// a.btn.account(href="/user/#{me.getSlugOrID()}", data-i18n="[title]play.account")
|
||||
// a.btn.settings(href='/account', data-i18n="[title]play.settings")
|
||||
|
||||
.user-status.header-font
|
||||
.user-status-line
|
||||
span.gem.gem-30
|
||||
span#gems-count.spr= me.gems()
|
||||
span.player-level-icon
|
||||
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
|
||||
span.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#volume-button(title="Adjust volume")
|
||||
.glyphicon.glyphicon-volume-off
|
||||
.glyphicon.glyphicon-volume-down
|
||||
.glyphicon.glyphicon-volume-up
|
||||
|
||||
//h1#campaign-status
|
||||
// if mapType == 'dungeon'
|
||||
// span.spr(data-i18n="play.campaign_dungeon")
|
||||
// else if mapType == 'forest'
|
||||
// span.spr(data-i18n="play.campaign_forest")
|
||||
// | -
|
||||
// if requiresSubscription
|
||||
// span.spl(data-i18n="play.subscription_required")
|
||||
// else if mapType == 'dungeon'
|
||||
// span.spl(data-i18n="play.free")
|
||||
// else
|
||||
// span.spl(data-i18n="play.subscribed")
|
|
@ -146,8 +146,10 @@ module.exports = class CampaignView extends RootView
|
|||
level.unlockedHero = level.unlocksHero.originalID in (me.get('earned')?.heroes or [])
|
||||
level.hidden = level.locked
|
||||
|
||||
@determineNextLevel context.levels if @sessions.loaded
|
||||
# put lower levels in last, so in the world map they layer over one another properly.
|
||||
context.campaign.levels = (_.sortBy context.campaign.levels, (l) -> l.position.y).reverse()
|
||||
context.levels = (_.sortBy context.levels, (l) -> l.position.y).reverse()
|
||||
@campaign.renderedLevels = context.levels
|
||||
|
||||
context.levelStatusMap = @levelStatusMap
|
||||
context.levelPlayCountMap = @levelPlayCountMap
|
||||
|
@ -155,8 +157,8 @@ module.exports = class CampaignView extends RootView
|
|||
context.mapType = _.string.slugify @terrain
|
||||
context.requiresSubscription = @requiresSubscription
|
||||
context.editorMode = @editorMode
|
||||
context.adjacentCampaigns = _.filter _.values(_.cloneDeep(@campaign.get('adjacentCampaigns') or {})), (ac) ->
|
||||
return false if ac.showIfUnlocked and ac.showIfUnlocked not in me.levels()
|
||||
context.adjacentCampaigns = _.filter _.values(_.cloneDeep(@campaign.get('adjacentCampaigns') or {})), (ac) =>
|
||||
return false if ac.showIfUnlocked and (ac.showIfUnlocked not in me.levels()) and not @editorMode
|
||||
ac.name = utils.i18n ac, 'name'
|
||||
ac.description = utils.i18n ac, 'description'
|
||||
styles = []
|
||||
|
@ -188,6 +190,11 @@ module.exports = class CampaignView extends RootView
|
|||
@updateHero()
|
||||
unless window.currentModal or not @fullyRendered
|
||||
@highlightElement '.level.next', delay: 500, duration: 60000, rotation: 0, sides: ['top']
|
||||
if @editorMode
|
||||
for level in @campaign.renderedLevels
|
||||
for nextLevelOriginal in level.nextLevels
|
||||
if nextLevel = _.find(@campaign.renderedLevels, original: nextLevelOriginal)
|
||||
@createLine level.position, nextLevel.position
|
||||
@applyCampaignStyles()
|
||||
|
||||
afterInsert: ->
|
||||
|
@ -199,6 +206,29 @@ module.exports = class CampaignView extends RootView
|
|||
authModal.mode = 'signup'
|
||||
@openModalView authModal
|
||||
|
||||
determineNextLevel: (levels) ->
|
||||
foundNext = false
|
||||
for level in levels
|
||||
level.nextLevels = (reward.level for reward in level.rewards when reward.level)
|
||||
unless foundNext
|
||||
for nextLevelOriginal in level.nextLevels
|
||||
nextLevel = _.find levels, original: nextLevelOriginal
|
||||
if nextLevel and not nextLevel.locked and @levelStatusMap[nextLevel.slug] isnt 'complete' and (me.isPremium() or not nextLevel.requiresSubscription)
|
||||
nextLevel.next = true
|
||||
foundNext = true
|
||||
break
|
||||
if not foundNext and levels[0] and not levels[0].locked and @levelStatusMap[levels[0].slug] isnt 'complete'
|
||||
levels[0].next = true
|
||||
|
||||
createLine: (o1, o2) ->
|
||||
p1 = x: o1.x, y: 0.66 * o1.y + 0.5
|
||||
p2 = x: o2.x, y: 0.66 * o2.y + 0.5
|
||||
length = Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))
|
||||
angle = Math.atan2(p1.y - p2.y, p2.x - p1.x) * 180 / Math.PI
|
||||
transform = "rotate(#{angle}deg)"
|
||||
line = $('<div>').appendTo('.map').addClass('next-level-line').css(transform: transform, width: length + '%', left: o1.x + '%', bottom: (o1.y + 0.5) + '%')
|
||||
line.append($('<div class="line">')).append($('<div class="point">'))
|
||||
|
||||
applyCampaignStyles: ->
|
||||
return unless @campaign.loaded
|
||||
if (backgrounds = @campaign.get 'backgroundImage') and backgrounds.length
|
||||
|
@ -221,7 +251,6 @@ module.exports = class CampaignView extends RootView
|
|||
return if @editorMode
|
||||
for session in @sessions.models
|
||||
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
|
||||
# TODO: add level.next = true for the next level they should do
|
||||
@render()
|
||||
|
||||
onClickMap: (e) ->
|
||||
|
|
Loading…
Reference in a new issue