Starting new front view (at /front for now) and play view (at /play-hero for now).
|
@ -14,7 +14,8 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
Backbone.Mediator.subscribe 'router:navigate', @onNavigate, @
|
||||
|
||||
routes:
|
||||
'': go('HomeView')
|
||||
'': go('HomeView') # This will go somewhere deprecated when FrontView is done.
|
||||
'front': go('FrontView') # This will become '' when it is done.
|
||||
|
||||
'about': go('AboutView')
|
||||
|
||||
|
@ -73,7 +74,8 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
|
||||
'multiplayer': go('MultiplayerView')
|
||||
|
||||
'play': go('play/MainPlayView')
|
||||
'play': go('play/MainPlayView') # This will become 'play-old' or something.
|
||||
'play-hero': go('play/WorldMapView') # This will become 'play' when it is done.
|
||||
'play/ladder/:levelID': go('play/ladder/LadderView')
|
||||
'play/ladder': go('play/ladder/MainLadderView')
|
||||
'play/level/:levelID': go('play/level/PlayLevelView')
|
||||
|
|
BIN
app/assets/images/pages/front/play_web.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
BIN
app/assets/images/pages/play/map_forest.jpg
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
app/assets/images/pages/play/menu_icons.png
Normal file
After Width: | Height: | Size: 83 KiB |
|
@ -131,6 +131,19 @@
|
|||
spectate: "Spectate"
|
||||
players: "players"
|
||||
hours_played: "hours played"
|
||||
items: "Items"
|
||||
heroes: "Heroes"
|
||||
achievements: "Achievements"
|
||||
account: "Account"
|
||||
settings: "Settings"
|
||||
|
||||
items:
|
||||
armor: "Armor"
|
||||
hands: "Hands"
|
||||
accessories: "Accessories"
|
||||
books: "Books"
|
||||
minions: "Minions"
|
||||
misc: "Misc"
|
||||
|
||||
contact:
|
||||
contact_us: "Contact CodeCombat"
|
||||
|
@ -878,7 +891,6 @@
|
|||
tutorial_play_first: "Play the Tutorial first."
|
||||
simple_ai: "Simple AI"
|
||||
warmup: "Warmup"
|
||||
vs: "VS"
|
||||
friends_playing: "Friends Playing"
|
||||
log_in_for_friends: "Log in to play with your friends!"
|
||||
social_connect_blurb: "Connect and play against your friends!"
|
||||
|
|
|
@ -104,7 +104,7 @@ NoteGroupSchema = c.object {title: 'Note Group', description: 'A group of notes
|
|||
target: c.shortString(title: 'Target', description: 'Target highlight element DOM selector string.')
|
||||
delay: {type: 'integer', minimum: 0, title: 'Delay', description: 'Show the highlight after this many milliseconds. Doesn\'t affect the dim shade cutout highlight method.'}
|
||||
offset: _.extend _.cloneDeep(PointSchema), {title: 'Offset', description: 'Pointing arrow tip offset in pixels from the default target.', format: null}
|
||||
rotation: {type: 'number', minimum: 0, title: 'Rotation', description: 'Rotation of the pointing arrow, in radians. PI / 2 points left, PI points up, etc.'}
|
||||
rotation: {type: 'number', minimum: 0, title: 'Rotation', description: 'Rotation of the pointing arrow, in radians. PI / 2 points left, PI points up, etc.', format: 'radians'}
|
||||
sides: c.array {title: 'Sides', description: 'Which sides of the target element to point at.'}, {type: 'string', 'enum': ['left', 'right', 'top', 'bottom'], title: 'Side', description: 'A side of the target element to point at.'}
|
||||
lock: {title: 'Lock', description: 'Whether the interface should be locked so that the player\'s focus is on the script, or specific areas to lock.', type: ['boolean', 'array'], items: {type: 'string', enum: ['surface', 'editor', 'palette', 'hud', 'playback', 'playback-hover', 'level']}}
|
||||
letterbox: {type: 'boolean', title: 'Letterbox', description: 'Turn letterbox mode on or off. Disables surface and playback controls.'}
|
||||
|
|
30
app/styles/front-view.sass
Normal file
|
@ -0,0 +1,30 @@
|
|||
@import "bootstrap/mixins"
|
||||
@import "bootstrap/variables"
|
||||
|
||||
#front-view
|
||||
h1
|
||||
text-align: center
|
||||
margin-top: 0
|
||||
|
||||
.platform-choices
|
||||
a
|
||||
text-align: center
|
||||
|
||||
.panel
|
||||
@include transition(background-color 0.5s ease)
|
||||
|
||||
&:hover
|
||||
text-decoration: none
|
||||
|
||||
.panel
|
||||
background-color: rgb(230, 230, 255)
|
||||
|
||||
.platform-ios
|
||||
img
|
||||
transform: scaleY(-1)
|
||||
|
||||
@media only screen and (max-width: 800px)
|
||||
#front-view
|
||||
#site-slogan
|
||||
font-size: 30px
|
||||
margin-bottom: 30px
|
|
@ -47,3 +47,17 @@
|
|||
color: black
|
||||
text-shadow: 0 1px 0 white
|
||||
|
||||
|
||||
.modal.play-modal
|
||||
.modal-header
|
||||
border: 0
|
||||
text-align: center
|
||||
padding: 0
|
||||
margin: 0 25px
|
||||
|
||||
h3
|
||||
margin-bottom: 0
|
||||
|
||||
.modal-body
|
||||
padding-top: 0
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
height: 100px
|
||||
overflow: hidden
|
||||
background: white
|
||||
border: 1px solid #333
|
||||
border-radius: 5px
|
||||
border-radius: 8px
|
||||
position: relative
|
||||
-webkit-transition: opacity 0.3s ease-in-out
|
||||
-moz-transition: opacity 0.3s ease-in-out
|
||||
|
@ -46,15 +45,15 @@
|
|||
.my-team-icon
|
||||
height: 60px
|
||||
position: relative
|
||||
top: -10px
|
||||
left: 10px
|
||||
top: -3.5px
|
||||
left: 13.5px
|
||||
z-index: 0
|
||||
|
||||
.opponent-team-icon
|
||||
height: 60px
|
||||
position: relative
|
||||
top: 10px
|
||||
right: 10px
|
||||
top: 16.5px
|
||||
right: 13.5px
|
||||
z-index: 0
|
||||
float: right
|
||||
-moz-transform: scaleX(-1)
|
||||
|
@ -78,19 +77,19 @@
|
|||
z-index: 1
|
||||
|
||||
.name-label
|
||||
border-bottom: 20px solid lightslategray
|
||||
height: 0
|
||||
height: 20px
|
||||
width: 40%
|
||||
position: absolute
|
||||
bottom: 0
|
||||
color: black
|
||||
color: white
|
||||
font-weight: bold
|
||||
text-shadow: -1px -1px 0px black
|
||||
text-align: center
|
||||
z-index: 2
|
||||
|
||||
span
|
||||
position: relative
|
||||
top: 1px
|
||||
top: 4px
|
||||
|
||||
.code-language
|
||||
position: absolute
|
||||
|
@ -116,9 +115,6 @@
|
|||
right: 3px
|
||||
|
||||
.difficulty
|
||||
border-top: 25px solid darkgray
|
||||
border-left: 20px solid transparent
|
||||
border-right: 20px solid transparent
|
||||
height: 0
|
||||
width: 30%
|
||||
position: absolute
|
||||
|
@ -131,17 +127,21 @@
|
|||
|
||||
span
|
||||
position: relative
|
||||
top: -25px
|
||||
top: 6px
|
||||
|
||||
.play-option
|
||||
background-image: url(/images/pages/play/ladder/warmup_button.png)
|
||||
|
||||
.easy-option .difficulty
|
||||
border-top: 25px solid limegreen
|
||||
.easy-option
|
||||
background-image: url(/images/pages/play/ladder/easy_button.png)
|
||||
|
||||
.medium-option .difficulty
|
||||
border-top: 25px solid darkorange
|
||||
.medium-option
|
||||
background-image: url(/images/pages/play/ladder/medium_button.png)
|
||||
|
||||
.hard-option .difficulty
|
||||
border-top: 25px solid black
|
||||
color: white
|
||||
.hard-option
|
||||
background-image: url(/images/pages/play/ladder/hard_button.png)
|
||||
.difficulty
|
||||
color: white
|
||||
|
||||
.vs
|
||||
position: absolute
|
||||
|
|
4
app/styles/play/modal/play-account-modal.sass
Normal file
|
@ -0,0 +1,4 @@
|
|||
#play-account-modal
|
||||
.account-view
|
||||
color: black
|
||||
|
4
app/styles/play/modal/play-achievements-modal.sass
Normal file
|
@ -0,0 +1,4 @@
|
|||
#play-achievements-modal
|
||||
.achievement-view
|
||||
color: black
|
||||
|
4
app/styles/play/modal/play-heroes-modal.sass
Normal file
|
@ -0,0 +1,4 @@
|
|||
#play-heroes-modal
|
||||
.hero-view
|
||||
color: black
|
||||
|
8
app/styles/play/modal/play-items-modal.sass
Normal file
|
@ -0,0 +1,8 @@
|
|||
#play-items-modal
|
||||
.item-view
|
||||
width: 420px
|
||||
float: left
|
||||
background-color: white
|
||||
border-radius: 6px
|
||||
margin: 5px
|
||||
|
4
app/styles/play/modal/play-settings-modal.sass
Normal file
|
@ -0,0 +1,4 @@
|
|||
#play-settings-modal
|
||||
.settings-view
|
||||
color: black
|
||||
|
151
app/styles/play/world-map-view.sass
Normal file
|
@ -0,0 +1,151 @@
|
|||
@import "app/styles/bootstrap/mixins"
|
||||
@import "app/styles/bootstrap/variables"
|
||||
|
||||
$forestMapWidth: 2500
|
||||
$forestMapHeight: 1536
|
||||
$forestMapSeaBackground: #71bad0
|
||||
$levelDotWidth: 2%
|
||||
$levelDotHeight: $levelDotWidth * $forestMapWidth / $forestMapHeight
|
||||
$levelDotZ: $levelDotHeight * 0.25
|
||||
$levelDotHoverZ: $levelDotZ * 2
|
||||
$levelDotShadowWidth: 0.8 * $levelDotWidth
|
||||
$levelDotShadowHeight: 0.8 * $levelDotHeight
|
||||
$levelClickRadius: 40px
|
||||
$gameControlSize: 80px
|
||||
$gameControlMargin: 40px
|
||||
|
||||
#world-map-view
|
||||
width: 100%
|
||||
height: 100%
|
||||
background-color: $forestMapSeaBackground
|
||||
|
||||
.map
|
||||
//background: white url("/images/pages/play/map_forest.jpg") no-repeat center center
|
||||
position: relative
|
||||
|
||||
.map-background
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
.level, .level-shadow
|
||||
position: absolute
|
||||
border-radius: 100%
|
||||
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
|
||||
opacity: 0.7
|
||||
|
||||
&.first
|
||||
width: 2 * $levelDotWidth
|
||||
height: 2 * $levelDotHeight
|
||||
margin-left: -0.5 * 2 * $levelDotWidth
|
||||
margin-bottom: -2 * $levelDotHeight / 3 + 2 * $levelDotZ
|
||||
|
||||
.level-shadow
|
||||
z-index: 1
|
||||
width: $levelDotShadowWidth
|
||||
height: $levelDotShadowHeight
|
||||
margin-left: -0.5 * $levelDotShadowWidth
|
||||
margin-bottom: -$levelDotShadowHeight / 3
|
||||
background-color: black
|
||||
box-shadow: 0px 0px 10px black
|
||||
@include opacity(0.75)
|
||||
|
||||
&.first
|
||||
width: 2 * $levelDotShadowWidth
|
||||
height: 2 * $levelDotShadowHeight
|
||||
margin-left: -0.5 * 2 * $levelDotShadowWidth
|
||||
margin-bottom: -2 * $levelDotShadowHeight / 3
|
||||
|
||||
.level:hover
|
||||
margin-bottom: -$levelDotHeight / 3 + $levelDotHoverZ
|
||||
|
||||
.level
|
||||
a
|
||||
display: block
|
||||
padding: $levelClickRadius
|
||||
margin-left: -0.5 * $levelClickRadius
|
||||
margin-top: -0.5 * $levelClickRadius
|
||||
border-radius: $levelClickRadius
|
||||
|
||||
&.first a
|
||||
padding: 2 * $levelClickRadius
|
||||
margin-left: 2 * -0.5 * $levelClickRadius
|
||||
margin-top: 2 * -0.5 * $levelClickRadius
|
||||
border-radius: 2 * $levelClickRadius
|
||||
|
||||
.level-info-container
|
||||
display: none
|
||||
position: absolute
|
||||
z-index: 3
|
||||
padding: 10px 10px 30px 10px
|
||||
border-image: url(/images/level/popover_background.png) 18 fill round
|
||||
border-width: 15px
|
||||
|
||||
.level-image
|
||||
float: left
|
||||
margin-right: 20px
|
||||
|
||||
.level-info.complete h3:after
|
||||
content: " - Complete!"
|
||||
color: green
|
||||
|
||||
.level-info.started h3:after
|
||||
content: " - Started"
|
||||
color: desaturate(green, 50%)
|
||||
|
||||
.level-info
|
||||
width: 330px
|
||||
float: left
|
||||
|
||||
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
|
||||
|
||||
.game-controls
|
||||
position: absolute
|
||||
right: 1%
|
||||
bottom: 1%
|
||||
|
||||
button.btn
|
||||
&:not(:first-child)
|
||||
margin-left: $gameControlMargin
|
||||
width: $gameControlSize
|
||||
height: $gameControlSize
|
||||
background: url(/images/pages/play/menu_icons.png) no-repeat
|
||||
background-size: cover
|
||||
@include transition(0.5s ease)
|
||||
box-shadow: 0 0 0 #bbf
|
||||
border: 0
|
||||
border-radius: 12px
|
||||
|
||||
&:hover
|
||||
box-shadow: 0 0 12px #bbf
|
||||
|
||||
&:active
|
||||
box-shadow: 0 0 20px white
|
||||
|
||||
&.heroes
|
||||
background-position-x: -1 * $gameControlSize
|
||||
&.achievements
|
||||
background-position-x: -2 * $gameControlSize
|
||||
&.account
|
||||
background-position-x: -3 * $gameControlSize
|
||||
&.settings
|
||||
background-position-x: -4 * $gameControlSize
|
28
app/templates/front-view.jade
Normal file
|
@ -0,0 +1,28 @@
|
|||
extends /templates/base
|
||||
|
||||
block content
|
||||
|
||||
.page-header
|
||||
h1#site-slogan
|
||||
span(data-i18n="home.slogan") Learn to Code by Playing a Game
|
||||
small.spl.spr -
|
||||
small free!
|
||||
|
||||
.row.platform-choices
|
||||
.col-xs-6.platform-ios
|
||||
a(href="#")
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h1 Play on iPad
|
||||
img.img-responsive(src="/images/pages/front/play_web.jpg")
|
||||
p.lead Get the app!
|
||||
|
||||
.col-xs-6.platform-web
|
||||
a(href="/play-hero")
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h1 Play on web
|
||||
img.img-responsive(src="/images/pages/front/play_web.jpg")
|
||||
p.lead Play right now!
|
||||
|
||||
.clearfix
|
26
app/templates/front.jade
Normal file
|
@ -0,0 +1,26 @@
|
|||
extends /templates/base
|
||||
|
||||
block content
|
||||
|
||||
.page-header
|
||||
h1#site-slogan
|
||||
span(data-i18n="home.slogan") Learn to Code by Playing a Game
|
||||
small.spl.spr -
|
||||
small free!
|
||||
|
||||
.row.platform-choices
|
||||
.col-xs-6.platform-ios
|
||||
a(href="#")
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h1 Play on iPad
|
||||
em - get the app!
|
||||
|
||||
.col-xs-6.platform-web
|
||||
a(href="/play")
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h1 Play on web
|
||||
em - play right now!
|
||||
|
||||
.clearfix
|
|
@ -6,14 +6,20 @@
|
|||
if closeButton
|
||||
.button.close(type="button", data-dismiss="modal", aria-hidden="true") ×
|
||||
block modal-header-content
|
||||
h3 man bites God
|
||||
if headerContent
|
||||
h3!= headerContent
|
||||
else
|
||||
h3 man bites God
|
||||
|
||||
block modal-body
|
||||
.modal-body
|
||||
block modal-body-content
|
||||
p Man Bites God are the bad boys of the Melbourne live music and comedy scene. It is like being drowned in a bathtub of harmony.
|
||||
img(src="http://www.manbitesgod.com/images/picturecoupleb.jpg")
|
||||
img(src="http://www.manbitesgod.com/images/manrantb.jpg")
|
||||
if bodyContent
|
||||
div!= bodyContent
|
||||
else
|
||||
p Man Bites God are the bad boys of the Melbourne live music and comedy scene. It is like being drowned in a bathtub of harmony.
|
||||
img(src="http://www.manbitesgod.com/images/picturecoupleb.jpg")
|
||||
img(src="http://www.manbitesgod.com/images/manrantb.jpg")
|
||||
|
||||
.modal-body.wait.secret
|
||||
block modal-body-wait-content
|
||||
|
|
|
@ -37,7 +37,6 @@ block modal-body-content
|
|||
//span.code-language(style="background-image: url(/images/common/code_languages/javascript_small.png)")
|
||||
div.difficulty
|
||||
span(data-i18n="ladder.warmup") Warmup
|
||||
div(data-i18n="ladder.vs").vs VS
|
||||
|
||||
if challengers.easy
|
||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.easy.sessionID}")
|
||||
|
@ -54,7 +53,6 @@ block modal-body-content
|
|||
span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.easy.codeLanguage + "_small.png)")
|
||||
div.difficulty
|
||||
span(data-i18n="general.easy") Easy
|
||||
div(data-i18n="ladder.vs").vs VS
|
||||
|
||||
if challengers.medium
|
||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.medium.sessionID}")
|
||||
|
@ -71,7 +69,6 @@ block modal-body-content
|
|||
span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.medium.codeLanguage + "_small.png)")
|
||||
div.difficulty
|
||||
span(data-i18n="general.medium") Medium
|
||||
div(data-i18n="ladder.vs").vs VS
|
||||
|
||||
if challengers.hard
|
||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.hard.sessionID}")
|
||||
|
@ -88,6 +85,5 @@ block modal-body-content
|
|||
span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.hard.codeLanguage + "_small.png)")
|
||||
div.difficulty
|
||||
span(data-i18n="general.hard") Hard
|
||||
div(data-i18n="ladder.vs").vs VS
|
||||
|
||||
block modal-footer
|
7
app/templates/play/modal/play-account-modal.jade
Normal file
|
@ -0,0 +1,7 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3(data-i18n="play.account") Account
|
||||
|
||||
block modal-body-content
|
||||
p TODO: show all dem account
|
7
app/templates/play/modal/play-achievements-modal.jade
Normal file
|
@ -0,0 +1,7 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3(data-i18n="play.achievements") Achievements
|
||||
|
||||
block modal-body-content
|
||||
p TODO: show all dem achievements
|
7
app/templates/play/modal/play-heroes-modal.jade
Normal file
|
@ -0,0 +1,7 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3(data-i18n="play.heroes") Heroes
|
||||
|
||||
block modal-body-content
|
||||
p TODO: show all dem heroes
|
17
app/templates/play/modal/play-items-modal.jade
Normal file
|
@ -0,0 +1,17 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3(data-i18n="play.items") Items
|
||||
|
||||
block modal-body-content
|
||||
ul.nav.nav-tabs
|
||||
for slotGroup, index in slotGroupsArray
|
||||
li(class=index ? "" : "active")
|
||||
a(href="#slot-group-" + slotGroup, data-toggle="tab")
|
||||
span= slotGroupsNames[index]
|
||||
.tab-content
|
||||
for slotGroup, index in slotGroupsArray
|
||||
.tab-pane(id="slot-group-" + slotGroup, class=index ? "" : "active")
|
||||
h3 buy some #{slotGroupsNames[index]} yo:
|
||||
for item in slotGroups[slotGroup]
|
||||
.replace-me(data-item-id=item.id)
|
7
app/templates/play/modal/play-settings-modal.jade
Normal file
|
@ -0,0 +1,7 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3(data-i18n="play.settings") Settings
|
||||
|
||||
block modal-body-content
|
||||
p TODO: show all dem settings
|
34
app/templates/play/world-map-view.jade
Normal file
|
@ -0,0 +1,34 @@
|
|||
.map
|
||||
img.map-background(src="/images/pages/play/map_forest.jpg", alt="")
|
||||
|
||||
each campaign in campaigns
|
||||
each level in campaign.levels
|
||||
div(style="left: #{level.x}%; bottom: #{level.y}%; background-color: #{campaign.color}", class="level" + (level.first ? " first" : "") + (level.disabled ? " disabled" : ""), data-level-id=level.id)
|
||||
a(href=level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.id}", disabled=level.disabled, class=levelStatusMap[level.id] || "")
|
||||
div(style="left: #{level.x}%; bottom: #{level.y}%", class="level-shadow" + (level.first ? " first" : ""))
|
||||
.level-info-container(data-level-id=level.id)
|
||||
if level.image
|
||||
img.level-image(src="#{level.image}", alt="#{level.name}")
|
||||
else
|
||||
img.level-image(src="/images/generic-icon.png", alt="#{level.name}")
|
||||
div(class="level-info " + (levelStatusMap[level.id] || ""))
|
||||
h3= level.name + (level.disabled ? " (Coming soon!)" : "")
|
||||
.level-description= level.description
|
||||
span(data-i18n="play.level_difficulty") Difficulty:
|
||||
each i in Array(level.difficulty)
|
||||
i.icon-star
|
||||
- var playCount = levelPlayCountMap[level.id]
|
||||
if playCount
|
||||
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
|
||||
|
||||
.game-controls
|
||||
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")
|
||||
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")
|
34
app/views/FrontView.coffee
Normal file
|
@ -0,0 +1,34 @@
|
|||
RootView = require 'views/kinds/RootView'
|
||||
template = require 'templates/front-view'
|
||||
{me} = require '/lib/auth'
|
||||
ModalView = require 'views/kinds/ModalView'
|
||||
|
||||
module.exports = class FrontView extends RootView
|
||||
id: 'front-view'
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .platform-ios a': 'onIOSClicked'
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
if $.browser
|
||||
majorVersion = $.browser.versionNumber
|
||||
c.isOldBrowser = true if $.browser.mozilla && majorVersion < 21
|
||||
c.isOldBrowser = true if $.browser.chrome && majorVersion < 17
|
||||
c.isOldBrowser = true if $.browser.safari && majorVersion < 6
|
||||
else
|
||||
console.warn 'no more jquery browser version...'
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
||||
onIOSClicked: (e) ->
|
||||
header = 'Sorry, the iPad app isn\'t ready yet'
|
||||
body = '''
|
||||
<p class="lead">We are working on it!</p>
|
||||
<p>For now, try playing on the web, and totally sign up (with emails enabled) so you can be the first to hear when it is ready.</p>
|
||||
'''
|
||||
notImplementedModal = new ModalView headerContent: header, bodyContent: body
|
||||
@openModalView notImplementedModal
|
|
@ -41,6 +41,7 @@ module.exports = class GameMenuModal extends ModalView
|
|||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-tab-switch', volume: 1
|
||||
|
||||
onHidden: ->
|
||||
super()
|
||||
subview.onHidden?() for subviewKey, subview of @subviews
|
||||
me.patch()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
||||
|
|
|
@ -176,7 +176,7 @@ module.exports = class CocoView extends Backbone.View
|
|||
target = elem.data('target')
|
||||
Modal = require 'views/'+target
|
||||
e.stopPropagation()
|
||||
@openModalView new Modal
|
||||
@openModalView new Modal supermodel: @supermodal
|
||||
|
||||
openModalView: (modalView, softly=false) ->
|
||||
return if waitingModal # can only have one waiting at once
|
||||
|
|
|
@ -7,6 +7,7 @@ module.exports = class ModalView extends CocoView
|
|||
modalWidthPercent: null
|
||||
plain: false
|
||||
instant: false
|
||||
template: require 'templates/modal/modal_base'
|
||||
|
||||
events:
|
||||
'click a': 'toggleModal'
|
||||
|
@ -26,6 +27,8 @@ module.exports = class ModalView extends CocoView
|
|||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context.closeButton = @closeButton
|
||||
context.headerContent = @options.headerContent
|
||||
context.bodyContent = @options.bodyContent
|
||||
context
|
||||
|
||||
subscriptions:
|
||||
|
|
472
app/views/play/WorldMapView.coffee
Normal file
|
@ -0,0 +1,472 @@
|
|||
RootView = require 'views/kinds/RootView'
|
||||
template = require 'templates/play/world-map-view'
|
||||
LevelSession = require 'models/LevelSession'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
AudioPlayer = require 'lib/AudioPlayer'
|
||||
|
||||
class LevelSessionsCollection extends CocoCollection
|
||||
url: ''
|
||||
model: LevelSession
|
||||
|
||||
constructor: (model) ->
|
||||
super()
|
||||
@url = "/db/user/#{me.id}/level.sessions?project=state.complete,levelID"
|
||||
|
||||
module.exports = class MainPlayView extends RootView
|
||||
id: 'world-map-view'
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .map': 'onClickMap'
|
||||
'click .game-controls button': 'onClickGameControl'
|
||||
'mouseenter .level a': 'onMouseEnterLevel'
|
||||
'mouseleave .level a': 'onMouseLeaveLevel'
|
||||
'mousemove .map': 'onMouseMoveMap'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
@levelStatusMap = {}
|
||||
@levelPlayCountMap = {}
|
||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
|
||||
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
||||
@getLevelPlayCounts()
|
||||
$(window).on 'resize', @onWindowResize
|
||||
|
||||
getLevelPlayCounts: ->
|
||||
success = (levelPlayCounts) =>
|
||||
return if @destroyed
|
||||
for level in levelPlayCounts
|
||||
@levelPlayCountMap[level._id] = playtime: level.playtime, sessions: level.sessions
|
||||
@render() if @supermodel.finished()
|
||||
|
||||
levelIDs = []
|
||||
for campaign in campaigns
|
||||
for level in campaign.levels
|
||||
levelIDs.push level.id
|
||||
levelPlayCountsRequest = @supermodel.addRequestResource 'play_counts', {
|
||||
url: '/db/level/-/play_counts'
|
||||
data: {ids: levelIDs}
|
||||
method: 'POST'
|
||||
success: success
|
||||
}, 0
|
||||
levelPlayCountsRequest.load()
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context.campaigns = campaigns
|
||||
for campaign in context.campaigns
|
||||
for level in campaign.levels
|
||||
level.x ?= 10 + 80 * Math.random()
|
||||
level.y ?= 10 + 80 * Math.random()
|
||||
context.levelStatusMap = @levelStatusMap
|
||||
context.levelPlayCountMap = @levelPlayCountMap
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
@onWindowResize()
|
||||
_.defer => @$el.find('.game-controls button').tooltip() # Have to defer or i18n doesn't take effect.
|
||||
|
||||
onSessionsLoaded: (e) ->
|
||||
for session in @sessions.models
|
||||
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
|
||||
@render()
|
||||
|
||||
onClickMap: (e) ->
|
||||
# Easy-ish way of figuring out coordinates for placing level dots.
|
||||
x = e.offsetX / @$el.find('.map-background').width()
|
||||
y = (1 - e.offsetY / @$el.find('.map-background').height())
|
||||
console.log " x: #{(100 * x).toFixed(2)}\n y: #{(100 * y).toFixed(2)}\n"
|
||||
|
||||
onClickGameControl: (e) ->
|
||||
|
||||
|
||||
onMouseEnterLevel: (e) ->
|
||||
levelID = $(e.target).parents('.level').data('level-id')
|
||||
@$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show()
|
||||
@adjustLevelInfoPosition e
|
||||
|
||||
onMouseLeaveLevel: (e) ->
|
||||
levelID = $(e.target).parents('.level').data('level-id')
|
||||
@$el.find(".level-info-container[data-level-id='#{levelID}']").hide()
|
||||
|
||||
onMouseMoveMap: (e) ->
|
||||
@adjustLevelInfoPosition e
|
||||
|
||||
adjustLevelInfoPosition: (e) ->
|
||||
return unless @$levelInfo
|
||||
@$map ?= @$el.find('.map')
|
||||
mapOffset = @$map.offset()
|
||||
mapX = e.pageX - mapOffset.left
|
||||
mapY = e.pageY - mapOffset.top
|
||||
margin = 20
|
||||
width = @$levelInfo.outerWidth()
|
||||
@$levelInfo.css('left', Math.min(Math.max(margin, mapX - width / 2), @$map.width() - width - margin))
|
||||
height = @$levelInfo.outerHeight()
|
||||
top = mapY - @$levelInfo.outerHeight() - 60
|
||||
if top < 20
|
||||
top = mapY + 60
|
||||
@$levelInfo.css('top', top)
|
||||
|
||||
onWindowResize: (e) =>
|
||||
forestMapWidth = 2401
|
||||
forestMapHeight = 1536
|
||||
aspectRatio = forestMapWidth / forestMapHeight
|
||||
pageWidth = $(window).width()
|
||||
pageHeight = $(window).height()
|
||||
widthRatio = pageWidth / forestMapWidth
|
||||
heightRatio = pageHeight / forestMapHeight
|
||||
if widthRatio > heightRatio
|
||||
resultingWidth = pageWidth
|
||||
resultingHeight = resultingWidth / aspectRatio
|
||||
else
|
||||
resultingHeight = pageHeight
|
||||
resultingWidth = resultingHeight * aspectRatio
|
||||
resultingMarginX = (pageWidth - resultingWidth) / 2
|
||||
resultingMarginY = (pageHeight - resultingHeight) / 2
|
||||
@$el.find('.map').css(width: resultingWidth, height: resultingHeight, 'margin-left': resultingMarginX, 'margin-top': resultingMarginY)
|
||||
|
||||
tutorials = [
|
||||
{
|
||||
name: 'Rescue Mission'
|
||||
difficulty: 1
|
||||
id: 'rescue-mission'
|
||||
image: '/file/db/level/52740644904ac0411700067c/rescue_mission_icon.png'
|
||||
description: 'Tharin has been captured! Start here.'
|
||||
first: true
|
||||
x: 17.23
|
||||
y: 36.94
|
||||
}
|
||||
{
|
||||
name: 'Grab the Mushroom'
|
||||
difficulty: 1
|
||||
id: 'grab-the-mushroom'
|
||||
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
|
||||
description: 'Grab a powerup and smash a big ogre.'
|
||||
x: 22.6
|
||||
y: 35.1
|
||||
}
|
||||
{
|
||||
name: 'Drink Me'
|
||||
difficulty: 1
|
||||
id: 'drink-me'
|
||||
image: '/file/db/level/525dc5589a0765e496000006/drink_me_icon.png'
|
||||
description: 'Drink up and slay two munchkins.'
|
||||
x: 27.74
|
||||
y: 35.17
|
||||
}
|
||||
{
|
||||
name: 'Taunt the Guards'
|
||||
difficulty: 1
|
||||
id: 'taunt-the-guards'
|
||||
image: '/file/db/level/5276c9bdcf83207a2801ff8f/taunt_icon.png'
|
||||
description: 'Tharin, if clever, can escape with Phoebe.'
|
||||
x: 32.7
|
||||
y: 36.7
|
||||
}
|
||||
{
|
||||
name: 'It\'s a Trap'
|
||||
difficulty: 1
|
||||
id: 'its-a-trap'
|
||||
image: '/file/db/level/528aea2d7f37fc4e0700016b/its_a_trap_icon.png'
|
||||
description: 'Organize a dungeon ambush with archers.'
|
||||
x: 37.6
|
||||
y: 40.0
|
||||
}
|
||||
{
|
||||
name: 'Break the Prison'
|
||||
difficulty: 1
|
||||
id: 'break-the-prison'
|
||||
image: '/file/db/level/5275272c69abdcb12401216e/break_the_prison_icon.png'
|
||||
description: 'More comrades are imprisoned!'
|
||||
x: 44.1
|
||||
y: 39.5
|
||||
}
|
||||
{
|
||||
name: 'Taunt'
|
||||
difficulty: 1
|
||||
id: 'taunt'
|
||||
image: '/file/db/level/525f150306e1ab0962000018/taunt_icon.png'
|
||||
description: 'Taunt the ogre to claim victory.'
|
||||
x: 38.5
|
||||
y: 44.1
|
||||
}
|
||||
{
|
||||
name: 'Cowardly Taunt'
|
||||
difficulty: 1
|
||||
id: 'cowardly-taunt'
|
||||
image: '/file/db/level/525abfd9b12777d78e000009/cowardly_taunt_icon.png'
|
||||
description: 'Lure infuriated ogres to their doom.'
|
||||
x: 39.2
|
||||
y: 50.1
|
||||
}
|
||||
{
|
||||
name: 'Commanding Followers'
|
||||
difficulty: 1
|
||||
id: 'commanding-followers'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: 'Lead allied soldiers into battle.'
|
||||
x: 39.1
|
||||
y: 54.7
|
||||
}
|
||||
{
|
||||
name: 'Mobile Artillery'
|
||||
difficulty: 1
|
||||
id: 'mobile-artillery'
|
||||
image: '/file/db/level/525085419851b83f4b000001/mobile_artillery_icon.png'
|
||||
description: 'Blow ogres up!'
|
||||
x: 39.5
|
||||
y: 60.2
|
||||
}
|
||||
]
|
||||
|
||||
experienced = [
|
||||
{
|
||||
name: 'Hunter Triplets'
|
||||
difficulty: 2
|
||||
id: 'hunter-triplets'
|
||||
image: '/file/db/level/526711d9add4f8965f000002/hunter_triplets_icon.png'
|
||||
description: 'Three soldiers go ogre hunting.'
|
||||
x: 51.76
|
||||
y: 35.5
|
||||
}
|
||||
{
|
||||
name: 'Emphasis on Aim'
|
||||
difficulty: 2
|
||||
id: 'emphasis-on-aim'
|
||||
image: '/file/db/level/525f384d96cd77000000000f/munchkin_masher_icon.png'
|
||||
description: 'Choose your targets carefully.'
|
||||
x: 61.47
|
||||
y: 33.46
|
||||
}
|
||||
{
|
||||
name: 'Zone of Danger'
|
||||
difficulty: 3
|
||||
id: 'zone-of-danger'
|
||||
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
|
||||
description: 'Target the ogres swarming into arrow range.'
|
||||
x: 65.72
|
||||
y: 26.72
|
||||
}
|
||||
{
|
||||
name: 'Molotov Medic'
|
||||
difficulty: 2
|
||||
id: 'molotov-medic'
|
||||
image: '/file/db/level/52602ecb026e8481e7000001/generic_1.png'
|
||||
description: 'Tharin must play support in this dungeon battle.'
|
||||
x: 70.95
|
||||
y: 18.64
|
||||
}
|
||||
{
|
||||
name: 'Gridmancer'
|
||||
difficulty: 5
|
||||
id: 'gridmancer'
|
||||
image: '/file/db/level/52ae2460ef42c52f13000008/gridmancer_icon.png'
|
||||
description: 'Super algorithm challenge level!'
|
||||
x: 61.41
|
||||
y: 17.22
|
||||
}
|
||||
]
|
||||
|
||||
arenas = [
|
||||
{
|
||||
name: 'Criss-Cross'
|
||||
difficulty: 5
|
||||
id: 'criss-cross'
|
||||
image: '/file/db/level/528aea2d7f37fc4e0700016b/its_a_trap_icon.png'
|
||||
description: 'Participate in a bidding war with opponents to reach the other side!'
|
||||
levelPath: 'ladder'
|
||||
x: 49.43
|
||||
y: 21.48
|
||||
}
|
||||
{
|
||||
name: 'Greed'
|
||||
difficulty: 4
|
||||
id: 'greed'
|
||||
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
|
||||
description: 'Liked Dungeon Arena and Gold Rush? Put them together in this economic arena!'
|
||||
levelPath: 'ladder'
|
||||
x: 45.00
|
||||
y: 23.34
|
||||
}
|
||||
{
|
||||
name: 'Dungeon Arena'
|
||||
difficulty: 3
|
||||
id: 'dungeon-arena'
|
||||
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
|
||||
description: 'Play head-to-head against fellow Wizards in a dungeon melee!'
|
||||
levelPath: 'ladder'
|
||||
x: 36.82
|
||||
y: 23.17
|
||||
}
|
||||
{
|
||||
name: 'Gold Rush'
|
||||
difficulty: 3
|
||||
id: 'gold-rush'
|
||||
image: '/file/db/level/52602ecb026e8481e7000001/generic_1.png'
|
||||
description: 'Prove you are better at collecting gold than your opponent!'
|
||||
levelPath: 'ladder'
|
||||
x: 30.8
|
||||
y: 16.87
|
||||
}
|
||||
{
|
||||
name: 'Brawlwood'
|
||||
difficulty: 4
|
||||
id: 'brawlwood'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: 'Combat the armies of other Wizards in a strategic forest arena! (Fast computer required.)'
|
||||
levelPath: 'ladder'
|
||||
x: 41.93
|
||||
y: 12.79
|
||||
}
|
||||
{
|
||||
name: 'Sky Span (Testing)'
|
||||
difficulty: 3
|
||||
id: 'sky-span'
|
||||
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
|
||||
description: 'Preview version of an upgraded Dungeon Arena. Help us with hero balance before release!'
|
||||
levelPath: 'ladder'
|
||||
x: 53.12
|
||||
y: 11.37
|
||||
}
|
||||
]
|
||||
|
||||
classicAlgorithms = [
|
||||
{
|
||||
name: 'Bubble Sort Bootcamp Battle'
|
||||
difficulty: 3
|
||||
id: 'bubble-sort-bootcamp-battle'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: 'Write a bubble sort to organize your soldiers. - by Alexandru Caciulescu'
|
||||
x: 26.37
|
||||
y: 93.02
|
||||
}
|
||||
{
|
||||
name: 'Ogres of Hanoi'
|
||||
difficulty: 3
|
||||
id: 'ogres-of-hanoi'
|
||||
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
|
||||
description: 'Transfer a stack of ogres while preserving their honor. - by Alexandru Caciulescu'
|
||||
x: 32.39
|
||||
y: 92.67
|
||||
}
|
||||
{
|
||||
name: 'Danger! Minefield'
|
||||
difficulty: 3
|
||||
id: 'danger-minefield'
|
||||
image: '/file/db/level/526bda3fe79aefde2a003e36/mobile_artillery_icon.png'
|
||||
description: 'Learn how to find prime numbers while defusing mines! - by Alexandru Caciulescu'
|
||||
x: 38.07
|
||||
y: 92.76
|
||||
}
|
||||
{
|
||||
name: 'K-means++ Cluster Wars'
|
||||
difficulty: 4
|
||||
id: 'k-means-cluster-wars'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: 'Learn cluster analysis while leading armies into battle! - by Alexandru Caciulescu'
|
||||
x: 43.75
|
||||
y: 90.36
|
||||
}
|
||||
{
|
||||
name: 'Quicksort the Spiral'
|
||||
difficulty: 3
|
||||
id: 'quicksort-the-spiral'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: 'Learn Quicksort while sorting a spiral of ogres! - by Alexandru Caciulescu'
|
||||
x: 48.97
|
||||
y: 87.08
|
||||
}
|
||||
{
|
||||
name: 'Minimax Tic-Tac-Toe'
|
||||
difficulty: 4
|
||||
id: 'minimax-tic-tac-toe'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: 'Learn how to make a game AI with the Minimax algorithm. - by Alexandru Caciulescu'
|
||||
x: 55.96
|
||||
y: 82.73
|
||||
}
|
||||
]
|
||||
|
||||
playerCreated = [
|
||||
{
|
||||
name: 'Extra Extrapolation'
|
||||
difficulty: 2
|
||||
id: 'extra-extrapolation'
|
||||
image: '/file/db/level/526bda3fe79aefde2a003e36/mobile_artillery_icon.png'
|
||||
description: 'Predict your target\'s position for deadly aim. - by Sootn'
|
||||
x: 42.67
|
||||
y: 67.98
|
||||
}
|
||||
{
|
||||
name: 'The Right Route'
|
||||
difficulty: 1
|
||||
id: 'the-right-route'
|
||||
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
|
||||
description: 'Strike at the weak point in an array of enemies. - by Aftermath'
|
||||
x: 47.38
|
||||
y: 70.55
|
||||
}
|
||||
{
|
||||
name: 'Sword Loop'
|
||||
difficulty: 2
|
||||
id: 'sword-loop'
|
||||
image: '/file/db/level/525dc5589a0765e496000006/drink_me_icon.png'
|
||||
description: 'Kill the ogres and save the peasants with for-loops. - by Prabh Simran Singh Baweja'
|
||||
x: 52.66
|
||||
y: 69.66
|
||||
}
|
||||
{
|
||||
name: 'Coin Mania'
|
||||
difficulty: 2
|
||||
id: 'coin-mania'
|
||||
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
|
||||
description: 'Learn while-loops to grab coins and potions. - by Prabh Simran Singh Baweja'
|
||||
x: 58.46
|
||||
y: 66.38
|
||||
}
|
||||
{
|
||||
name: 'Find the Spy'
|
||||
difficulty: 2
|
||||
id: 'find-the-spy'
|
||||
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
|
||||
description: 'Identify the spies hidden among your soldiers - by Nathan Gossett'
|
||||
x: 63.11
|
||||
y: 62.74
|
||||
}
|
||||
{
|
||||
name: 'Harvest Time'
|
||||
difficulty: 2
|
||||
id: 'harvest-time'
|
||||
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
|
||||
description: 'Collect a hundred mushrooms in just five lines of code - by Nathan Gossett'
|
||||
x: 69.19
|
||||
y: 60.61
|
||||
}
|
||||
{
|
||||
name: 'Guide Everyone Home'
|
||||
difficulty: 2
|
||||
id: 'guide-everyone-home'
|
||||
image: '/file/db/level/52740644904ac0411700067c/rescue_mission_icon.png'
|
||||
description: 'Fetch the wizards teleporting into the area - by Nathan Gossett'
|
||||
x: 77.54
|
||||
y: 65.94
|
||||
}
|
||||
{
|
||||
name: "Let's go Fly a Kite"
|
||||
difficulty: 3
|
||||
id: 'lets-go-fly-a-kite'
|
||||
image: '/file/db/level/526711d9add4f8965f000002/hunter_triplets_icon.png'
|
||||
description: 'There is a horde of ogres marching on your village. Stay out of reach and use your bow to take them out! - by Danny Whittaker'
|
||||
x: 84.29
|
||||
y: 61.23
|
||||
}
|
||||
]
|
||||
|
||||
campaigns = [
|
||||
{id: 'beginner', name: 'Beginner Campaign', description: '... in which you learn the wizardry of programming.', levels: tutorials, color: "rgb(255, 80, 60)"}
|
||||
{id: 'multiplayer', name: 'Multiplayer Arenas', description: '... in which you code head-to-head against other players.', levels: arenas, color: "rgb(80, 5, 60)"}
|
||||
{id: 'dev', name: 'Random Harder Levels', description: '... in which you learn the interface while doing something a little harder.', levels: experienced, color: "rgb(80, 60, 255)"}
|
||||
{id: 'classic' ,name: 'Classic Algorithms', description: '... in which you learn the most popular algorithms in Computer Science.', levels: classicAlgorithms, color: "rgb(110, 80, 120)"}
|
||||
{id: 'player_created', name: 'Player-Created', description: '... in which you battle against the creativity of your fellow <a href=\"/contribute#artisan\">Artisan Wizards</a>.', levels: playerCreated, color: "rgb(160, 160, 180)"}
|
||||
]
|
28
app/views/play/modal/PlayAccountModal.coffee
Normal file
|
@ -0,0 +1,28 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/play/modal/play-account-modal'
|
||||
|
||||
module.exports = class PlayAccountModal extends ModalView
|
||||
className: 'modal fade play-modal'
|
||||
template: template
|
||||
modalWidthPercent: 90
|
||||
id: 'play-account-modal'
|
||||
#instant: true
|
||||
|
||||
#events:
|
||||
# 'change input.select': 'onSelectionChanged'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
|
||||
|
||||
onHidden: ->
|
||||
super()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
35
app/views/play/modal/PlayAchievementsModal.coffee
Normal file
|
@ -0,0 +1,35 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/play/modal/play-achievements-modal'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
Achievement = require 'models/Achievement'
|
||||
#AchievementView = require 'views/game-menu/AchievementView'
|
||||
|
||||
module.exports = class PlayAchievementsModal extends ModalView
|
||||
className: 'modal fade play-modal'
|
||||
template: template
|
||||
modalWidthPercent: 90
|
||||
id: 'play-achievements-modal'
|
||||
#instant: true
|
||||
|
||||
#events:
|
||||
# 'change input.select': 'onSelectionChanged'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
#@achievements = new CocoCollection([], {model: Achievement})
|
||||
#@achievements.url = '/db/thang.type?view=achievements&project=name,description,components,original,rasterIcon'
|
||||
#@supermodel.loadCollection(@achievements, 'achievements')
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
#context.achievements = @achievements.models
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
|
||||
|
||||
onHidden: ->
|
||||
super()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
47
app/views/play/modal/PlayHeroesModal.coffee
Normal file
|
@ -0,0 +1,47 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/play/modal/play-heroes-modal'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
ThangType = require 'models/ThangType'
|
||||
#HeroView = require 'views/game-menu/HeroView'
|
||||
|
||||
module.exports = class PlayHeroesModal extends ModalView
|
||||
className: 'modal fade play-modal'
|
||||
template: template
|
||||
modalWidthPercent: 90
|
||||
id: 'play-heroes-modal'
|
||||
#instant: true
|
||||
|
||||
#events:
|
||||
# 'change input.select': 'onSelectionChanged'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
@heroes = new CocoCollection([], {model: ThangType})
|
||||
@heroes.url = '/db/thang.type?view=heroes&project=name,description,components,original,rasterIcon'
|
||||
@supermodel.loadCollection(@heroes, 'heroes')
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context.heroes = @heroes.models
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
|
||||
#@addHeroViews()
|
||||
|
||||
onHidden: ->
|
||||
super()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
||||
|
||||
#addHeroViews: ->
|
||||
# keys = (hero.id for hero in @heroes.models)
|
||||
# heroMap = _.zipObject keys, @heroes.models
|
||||
# for heroStub in @$el.find('.replace-me')
|
||||
# heroID = $(heroStub).data('hero-id')
|
||||
# hero = heroMap[heroID]
|
||||
# heroView = new HeroView({hero: hero, includes: {name: true, stats: true, props: true}})
|
||||
# heroView.render()
|
||||
# $(heroStub).replaceWith(heroView.$el)
|
||||
# @registerSubView(heroView)
|
66
app/views/play/modal/PlayItemsModal.coffee
Normal file
|
@ -0,0 +1,66 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/play/modal/play-items-modal'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
ThangType = require 'models/ThangType'
|
||||
ItemView = require 'views/game-menu/ItemView'
|
||||
|
||||
module.exports = class PlayItemsModal extends ModalView
|
||||
className: 'modal fade play-modal'
|
||||
template: template
|
||||
modalWidthPercent: 90
|
||||
id: 'play-items-modal'
|
||||
#instant: true
|
||||
slotGroups:
|
||||
armor: ['torso', 'head', 'gloves', 'feet']
|
||||
hands: ['right-hand', 'left-hand']
|
||||
accessories: ['eyes', 'neck', 'left-ring', 'right-ring', 'waist']
|
||||
books: ['programming-book', 'spellbook']
|
||||
minions: ['minion', 'pet']
|
||||
misc: ['misc-0', 'misc-1', 'misc-2', 'misc-3', 'misc-4']
|
||||
|
||||
#events:
|
||||
# 'change input.select': 'onSelectionChanged'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
@items = new CocoCollection([], {model: ThangType})
|
||||
@items.url = '/db/thang.type?view=items&project=name,description,components,original,rasterIcon'
|
||||
@supermodel.loadCollection(@items, 'items')
|
||||
|
||||
groupItems: ->
|
||||
groups = {}
|
||||
for item in @items.models
|
||||
itemSlots = item.getAllowedSlots()
|
||||
for group, groupSlots of @slotGroups
|
||||
if _.find itemSlots, ((slot) -> slot in groupSlots)
|
||||
groups[group] ?= []
|
||||
groups[group].push item
|
||||
groups
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context.slotGroups = @groupItems()
|
||||
context.slotGroupsArray = _.keys context.slotGroups
|
||||
context.slotGroupsNames = ($.i18n.t "items.#{slotGroup}" for slotGroup in context.slotGroupsArray)
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
|
||||
@addItemViews()
|
||||
|
||||
onHidden: ->
|
||||
super()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
||||
|
||||
addItemViews: ->
|
||||
keys = (item.id for item in @items.models)
|
||||
itemMap = _.zipObject keys, @items.models
|
||||
for itemStub in @$el.find('.replace-me')
|
||||
itemID = $(itemStub).data('item-id')
|
||||
item = itemMap[itemID]
|
||||
itemView = new ItemView({item: item, includes: {name: true, stats: true, props: true}})
|
||||
itemView.render()
|
||||
$(itemStub).replaceWith(itemView.$el)
|
||||
@registerSubView(itemView)
|
28
app/views/play/modal/PlaySettingsModal.coffee
Normal file
|
@ -0,0 +1,28 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/play/modal/play-settings-modal'
|
||||
|
||||
module.exports = class PlaySettingsModal extends ModalView
|
||||
className: 'modal fade play-modal'
|
||||
template: template
|
||||
modalWidthPercent: 90
|
||||
id: 'play-settings-modal'
|
||||
#instant: true
|
||||
|
||||
#events:
|
||||
# 'change input.select': 'onSelectionChanged'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
context = super(context)
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
|
||||
|
||||
onHidden: ->
|
||||
super()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|