Merge branch 'master' into production
This commit is contained in:
commit
0ad11fa7ef
25 changed files with 137 additions and 371 deletions
app
assets/images/pages/play/ladder
humans_ladder_easy.pnghumans_ladder_hard.pnghumans_ladder_medium.pnghumans_ladder_tutorial.pngogres_ladder_easy.pngogres_ladder_hard.pngogres_ladder_medium.pngogres_ladder_tutorial.png
lib
models
styles/play
templates/play
views
server/users
BIN
app/assets/images/pages/play/ladder/humans_ladder_easy.png
Normal file
BIN
app/assets/images/pages/play/ladder/humans_ladder_easy.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 22 KiB |
BIN
app/assets/images/pages/play/ladder/humans_ladder_hard.png
Normal file
BIN
app/assets/images/pages/play/ladder/humans_ladder_hard.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 24 KiB |
BIN
app/assets/images/pages/play/ladder/humans_ladder_medium.png
Normal file
BIN
app/assets/images/pages/play/ladder/humans_ladder_medium.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 18 KiB |
BIN
app/assets/images/pages/play/ladder/humans_ladder_tutorial.png
Normal file
BIN
app/assets/images/pages/play/ladder/humans_ladder_tutorial.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 22 KiB |
BIN
app/assets/images/pages/play/ladder/ogres_ladder_easy.png
Normal file
BIN
app/assets/images/pages/play/ladder/ogres_ladder_easy.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 22 KiB |
BIN
app/assets/images/pages/play/ladder/ogres_ladder_hard.png
Normal file
BIN
app/assets/images/pages/play/ladder/ogres_ladder_hard.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 25 KiB |
BIN
app/assets/images/pages/play/ladder/ogres_ladder_medium.png
Normal file
BIN
app/assets/images/pages/play/ladder/ogres_ladder_medium.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 23 KiB |
BIN
app/assets/images/pages/play/ladder/ogres_ladder_tutorial.png
Normal file
BIN
app/assets/images/pages/play/ladder/ogres_ladder_tutorial.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 26 KiB |
|
@ -19,7 +19,7 @@ module.exports = class CocoRouter extends Backbone.Router
|
||||||
'editor/:model(/:slug_or_id)(/:subview)': 'editorModelView'
|
'editor/:model(/:slug_or_id)(/:subview)': 'editorModelView'
|
||||||
|
|
||||||
# Experimenting with direct links
|
# Experimenting with direct links
|
||||||
'play/ladder/:levelID/team/:team': go('play/ladder/team_view')
|
# 'play/ladder/:levelID/team/:team': go('play/ladder/team_view')
|
||||||
|
|
||||||
# db and file urls call the server directly
|
# db and file urls call the server directly
|
||||||
'db/*path': 'routeToServer'
|
'db/*path': 'routeToServer'
|
||||||
|
|
|
@ -117,7 +117,6 @@ module.exports = class Level extends CocoModel
|
||||||
else if path is '/'
|
else if path is '/'
|
||||||
# We also we need to make sure we grab the Wizard ThangType and the Marks. Hackitrooooid!
|
# We also we need to make sure we grab the Wizard ThangType and the Marks. Hackitrooooid!
|
||||||
for [type, original] in [
|
for [type, original] in [
|
||||||
["Wizard", "52a00d55cf1818f2be00000b"]
|
|
||||||
["Highlight", "529f8fdbdacd325127000003"]
|
["Highlight", "529f8fdbdacd325127000003"]
|
||||||
["Selection", "52aa5f7520fccb0000000002"]
|
["Selection", "52aa5f7520fccb0000000002"]
|
||||||
["Target", "52b32ad97385ec3d03000001"]
|
["Target", "52b32ad97385ec3d03000001"]
|
||||||
|
@ -126,4 +125,5 @@ module.exports = class Level extends CocoModel
|
||||||
link = "/db/thang_type/#{original}/version"
|
link = "/db/thang_type/#{original}/version"
|
||||||
model = CocoModel.getOrMakeModelFromLink link, shouldLoadProjection
|
model = CocoModel.getOrMakeModelFromLink link, shouldLoadProjection
|
||||||
models.push model if model
|
models.push model if model
|
||||||
|
models.push ThangType.loadUniversalWizard()
|
||||||
models
|
models
|
||||||
|
|
|
@ -172,7 +172,10 @@ module.exports = class ThangType extends CocoModel
|
||||||
key = spriteOptionsOrKey
|
key = spriteOptionsOrKey
|
||||||
key = if _.isString(key) then key else @spriteSheetKey(@fillOptions(key))
|
key = if _.isString(key) then key else @spriteSheetKey(@fillOptions(key))
|
||||||
spriteSheet = @spriteSheets[key]
|
spriteSheet = @spriteSheets[key]
|
||||||
spriteSheet ?= @buildSpriteSheet({portraitOnly:true})
|
if not spriteSheet
|
||||||
|
options = if _.isPlainObject spriteOptionsOrKey then spriteOptionsOrKey else {}
|
||||||
|
options.portraitOnly = true
|
||||||
|
spriteSheet = @buildSpriteSheet(options)
|
||||||
return unless spriteSheet
|
return unless spriteSheet
|
||||||
canvas = $("<canvas width='#{size}' height='#{size}'></canvas>")
|
canvas = $("<canvas width='#{size}' height='#{size}'></canvas>")
|
||||||
stage = new createjs.Stage(canvas[0])
|
stage = new createjs.Stage(canvas[0])
|
||||||
|
@ -211,9 +214,11 @@ module.exports = class ThangType extends CocoModel
|
||||||
onFileUploaded: =>
|
onFileUploaded: =>
|
||||||
console.log 'Image uploaded'
|
console.log 'Image uploaded'
|
||||||
|
|
||||||
wizOriginal = "52a00d55cf1818f2be00000b"
|
@loadUniversalWizard: ->
|
||||||
url = "/db/thang_type/#{wizOriginal}/version"
|
return @wizardType if @wizardType
|
||||||
wizardType = new module.exports()
|
wizOriginal = "52a00d55cf1818f2be00000b"
|
||||||
wizardType.url = -> url
|
url = "/db/thang_type/#{wizOriginal}/version"
|
||||||
wizardType.fetch()
|
@wizardType = new module.exports()
|
||||||
module.exports.wizardType = wizardType
|
@wizardType.url = -> url
|
||||||
|
@wizardType.fetch()
|
||||||
|
@wizardType
|
|
@ -12,10 +12,6 @@
|
||||||
margin-bottom: 10px
|
margin-bottom: 10px
|
||||||
background-image: none
|
background-image: none
|
||||||
|
|
||||||
.intro-button
|
|
||||||
width: 45%
|
|
||||||
margin: 0 2.5%
|
|
||||||
|
|
||||||
.name-col-cell
|
.name-col-cell
|
||||||
max-width: 300px
|
max-width: 300px
|
||||||
text-overflow: ellipsis
|
text-overflow: ellipsis
|
||||||
|
|
|
@ -21,14 +21,45 @@
|
||||||
opacity: 0.4
|
opacity: 0.4
|
||||||
|
|
||||||
border-radius: 5px
|
border-radius: 5px
|
||||||
|
.only-one
|
||||||
|
-webkit-transition: opacity 0.3s ease-in-out
|
||||||
|
-moz-transition: opacity 0.3s ease-in-out
|
||||||
|
-ms-transition: opacity 0.3s ease-in-out
|
||||||
|
-o-transition: opacity 0.3s ease-in-out
|
||||||
|
transition: opacity 0.3s ease-in-out
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
.play-option:hover
|
.play-option:hover
|
||||||
opacity: 1
|
opacity: 1
|
||||||
|
.only-one
|
||||||
|
opacity: 1
|
||||||
|
|
||||||
.my-icon
|
.my-icon
|
||||||
position: relative
|
position: relative
|
||||||
left: 0
|
left: 0
|
||||||
top: -10px
|
top: -10px
|
||||||
|
z-index: 1
|
||||||
|
|
||||||
|
.my-team-icon
|
||||||
|
height: 60px
|
||||||
|
position: relative
|
||||||
|
top: -10px
|
||||||
|
left: 10px
|
||||||
|
z-index: 0
|
||||||
|
|
||||||
|
.opponent-team-icon
|
||||||
|
height: 60px
|
||||||
|
position: relative
|
||||||
|
top: 10px
|
||||||
|
right: 10px
|
||||||
|
z-index: 0
|
||||||
|
float: right
|
||||||
|
-moz-transform: scaleX(-1)
|
||||||
|
-o-transform: scaleX(-1)
|
||||||
|
-webkit-transform: scaleX(-1)
|
||||||
|
transform: scaleX(-1)
|
||||||
|
filter: FlipH
|
||||||
|
-ms-filter: "FlipH"
|
||||||
|
|
||||||
.opponent-icon
|
.opponent-icon
|
||||||
position: relative
|
position: relative
|
||||||
|
@ -41,6 +72,7 @@
|
||||||
transform: scaleX(-1)
|
transform: scaleX(-1)
|
||||||
filter: FlipH
|
filter: FlipH
|
||||||
-ms-filter: "FlipH"
|
-ms-filter: "FlipH"
|
||||||
|
z-index: 1
|
||||||
|
|
||||||
.name-label
|
.name-label
|
||||||
border-bottom: 20px solid lightslategray
|
border-bottom: 20px solid lightslategray
|
||||||
|
@ -51,6 +83,7 @@
|
||||||
color: black
|
color: black
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
text-align: center
|
text-align: center
|
||||||
|
z-index: 2
|
||||||
|
|
||||||
span
|
span
|
||||||
position: relative
|
position: relative
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#ladder-team-view
|
|
||||||
#rank-button
|
|
||||||
margin-top: 15px
|
|
||||||
|
|
||||||
#competitors-column .well
|
|
||||||
font-size: 18px
|
|
||||||
padding: 7px
|
|
||||||
|
|
||||||
#your-score
|
|
||||||
margin-top: 20px
|
|
||||||
text-align: center
|
|
||||||
font-size: 20px
|
|
|
@ -3,9 +3,6 @@ block content
|
||||||
|
|
||||||
div#level-column
|
div#level-column
|
||||||
h1= level.get('name')
|
h1= level.get('name')
|
||||||
|
|
||||||
//if !me.get('anonymous')
|
|
||||||
// a(href="/play/level/brawlwood-tutorial").intro-button.btn.btn-primary.btn-lg Play the Tutorial
|
|
||||||
|
|
||||||
if me.get('anonymous')
|
if me.get('anonymous')
|
||||||
div#must-log-in
|
div#must-log-in
|
||||||
|
|
|
@ -17,7 +17,5 @@ div#columns.row
|
||||||
td.score-cell= session.get('totalScore').toFixed(2)
|
td.score-cell= session.get('totalScore').toFixed(2)
|
||||||
td.name-col-cell= session.get('creatorName') || "Anonymous"
|
td.name-col-cell= session.get('creatorName') || "Anonymous"
|
||||||
td
|
td
|
||||||
if(!myRow)
|
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}")
|
||||||
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") Battle as #{team.otherTeam}!
|
span Battle as #{team.otherTeam}!
|
||||||
else
|
|
||||||
a(href="/play/ladder/#{levelID}/team/#{team.id}") View your #{team.id} matches.
|
|
|
@ -12,9 +12,11 @@ block modal-body-content
|
||||||
|
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}")
|
a(href="/play/level/#{levelID}?team=#{teamID}")
|
||||||
div.play-option
|
div.play-option
|
||||||
img(src=portraitSRC).my-icon
|
img(src=myPortrait).my-icon.only-one
|
||||||
img(src=portraitSRC).opponent-icon
|
img(src="/images/pages/play/ladder/"+teamID+"_ladder_tutorial.png", style="border: 1px solid #{teamColor}; background: #{teamBackgroundColor}").my-team-icon.img-circle.only-one
|
||||||
div.my-name.name-label
|
img(src=genericPortrait).opponent-icon
|
||||||
|
img(src="/images/pages/play/ladder/"+otherTeamID+"_ladder_tutorial.png", style="border: 1px solid #{opponentTeamColor}; background: #{opponentTeamBackgroundColor}").opponent-team-icon.img-circle
|
||||||
|
div.my-name.name-label.only-one
|
||||||
span= myName
|
span= myName
|
||||||
div.opponent-name.name-label
|
div.opponent-name.name-label
|
||||||
span Simple AI
|
span Simple AI
|
||||||
|
@ -25,9 +27,11 @@ block modal-body-content
|
||||||
if challengers.easy
|
if challengers.easy
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.easy.sessionID}")
|
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.easy.sessionID}")
|
||||||
div.play-option.easy-option
|
div.play-option.easy-option
|
||||||
img(src=portraitSRC).my-icon
|
img(src=myPortrait).my-icon.only-one
|
||||||
img(src=portraitSRC).opponent-icon
|
img(src="/images/pages/play/ladder/"+teamID+"_ladder_easy.png", style="border: 1px solid #{teamColor}; background: #{teamBackgroundColor}").my-team-icon.img-circle.only-one
|
||||||
div.my-name.name-label
|
img(src=challengers.easy.opponentImageSource||genericPortrait).opponent-icon
|
||||||
|
img(src="/images/pages/play/ladder/"+otherTeamID+"_ladder_easy.png", style="border: 1px solid #{opponentTeamColor}; background: #{opponentTeamBackgroundColor}").opponent-team-icon.img-circle
|
||||||
|
div.my-name.name-label.only-one
|
||||||
span= myName
|
span= myName
|
||||||
div.opponent-name.name-label
|
div.opponent-name.name-label
|
||||||
span= challengers.easy.opponentName
|
span= challengers.easy.opponentName
|
||||||
|
@ -38,9 +42,11 @@ block modal-body-content
|
||||||
if challengers.medium
|
if challengers.medium
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.medium.sessionID}")
|
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.medium.sessionID}")
|
||||||
div.play-option.medium-option
|
div.play-option.medium-option
|
||||||
img(src=portraitSRC).my-icon
|
img(src=myPortrait).my-icon.only-one
|
||||||
img(src=portraitSRC).opponent-icon
|
img(src="/images/pages/play/ladder/"+teamID+"_ladder_medium.png", style="border: 1px solid #{teamColor}; background: #{teamBackgroundColor}").my-team-icon.img-circle.only-one
|
||||||
div.my-name.name-label
|
img(src=challengers.medium.opponentImageSource||genericPortrait).opponent-icon
|
||||||
|
img(src="/images/pages/play/ladder/"+otherTeamID+"_ladder_medium.png", style="border: 1px solid #{opponentTeamColor}; background: #{opponentTeamBackgroundColor}").opponent-team-icon.img-circle
|
||||||
|
div.my-name.name-label.only-one
|
||||||
span= myName
|
span= myName
|
||||||
div.opponent-name.name-label
|
div.opponent-name.name-label
|
||||||
span= challengers.medium.opponentName
|
span= challengers.medium.opponentName
|
||||||
|
@ -51,9 +57,11 @@ block modal-body-content
|
||||||
if challengers.hard
|
if challengers.hard
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.hard.sessionID}")
|
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.hard.sessionID}")
|
||||||
div.play-option.hard-option
|
div.play-option.hard-option
|
||||||
img(src=portraitSRC).my-icon
|
img(src=myPortrait).my-icon.only-one
|
||||||
img(src=portraitSRC).opponent-icon
|
img(src="/images/pages/play/ladder/"+teamID+"_ladder_hard.png", style="border: 1px solid #{teamColor}; background: #{teamBackgroundColor}").my-team-icon.img-circle.only-one
|
||||||
div.my-name.name-label
|
img(src=challengers.hard.opponentImageSource||genericPortrait).opponent-icon
|
||||||
|
img(src="/images/pages/play/ladder/"+otherTeamID+"_ladder_hard.png", style="border: 1px solid #{opponentTeamColor}; background: #{opponentTeamBackgroundColor}").opponent-team-icon.img-circle
|
||||||
|
div.my-name.name-label.only-one
|
||||||
span= myName
|
span= myName
|
||||||
div.opponent-name.name-label
|
div.opponent-name.name-label
|
||||||
span= challengers.hard.opponentName
|
span= challengers.hard.opponentName
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
extends /templates/base
|
|
||||||
block content
|
|
||||||
|
|
||||||
ol.breadcrumb
|
|
||||||
li
|
|
||||||
a(href="/") Home
|
|
||||||
li
|
|
||||||
a(href="/play/ladder/#{levelID}")= level.get('name')
|
|
||||||
li.active= teamName
|
|
||||||
|
|
||||||
p
|
|
||||||
| In this level, you play against everyone who has ever written strategies for the opposing forces.
|
|
||||||
| Choose from the suggested players on the right, playing as many and as long as you like,
|
|
||||||
| and when you are ready to test your grand strategy against the whole ladder, return and click the rank button.
|
|
||||||
|
|
||||||
p
|
|
||||||
| After your first submission, your code will also continuously run against other players as they rank themselves.
|
|
||||||
|
|
||||||
if matches.length
|
|
||||||
p#your-score
|
|
||||||
span Your Current Score:
|
|
||||||
span
|
|
||||||
strong= score
|
|
||||||
|
|
||||||
|
|
||||||
div#columns.row
|
|
||||||
div#matches-column.col-md-6
|
|
||||||
h3.pull-left Ranked Games
|
|
||||||
button.btn.btn-warning.pull-right#rank-button
|
|
||||||
span.unavailable.hidden No New Code to Rank
|
|
||||||
span.rank.hidden Rank My Game!
|
|
||||||
span.ranking.hidden Submitting...
|
|
||||||
span.ranked.hidden Submitted for Ranking
|
|
||||||
span.failed.hidden Failed to Rank
|
|
||||||
|
|
||||||
hr.clearfix(style="clear: both")
|
|
||||||
|
|
||||||
if matches.length
|
|
||||||
table.table.table-bordered.table-condensed
|
|
||||||
tr
|
|
||||||
th Result
|
|
||||||
th Opponent
|
|
||||||
th When
|
|
||||||
for match in matches
|
|
||||||
tr
|
|
||||||
td.state-cell
|
|
||||||
if match.state === 'win'
|
|
||||||
span.win Win
|
|
||||||
if match.state === 'loss'
|
|
||||||
span.loss Loss
|
|
||||||
if match.state === 'tie'
|
|
||||||
span.tie Tie
|
|
||||||
td.name-cell= match.opponentName || "Anonymous"
|
|
||||||
td.time-cell= match.when
|
|
||||||
td.battle-cell
|
|
||||||
- var text = match.state === 'win' ? 'Watch your victory' : 'Defeat the ' + otherTeamID
|
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{match.sessionID}")= text
|
|
||||||
|
|
||||||
else
|
|
||||||
div.alert.alert-warning
|
|
||||||
| No ranked matches played yet!
|
|
||||||
| Play some competitors on the right and then come back to get your game ranked.
|
|
||||||
|
|
||||||
// finish this once matches are available
|
|
||||||
|
|
||||||
div#competitors-column.col-md-6
|
|
||||||
h3 Your Competitors
|
|
||||||
|
|
||||||
.well.text-muted
|
|
||||||
div.row
|
|
||||||
div.col-md-2
|
|
||||||
span.warmup Warmup
|
|
||||||
span :
|
|
||||||
div.col-md-10
|
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}")
|
|
||||||
span.warmup Play #{teamID} vs Default #{otherTeamID}
|
|
||||||
|
|
||||||
if challengers.easy
|
|
||||||
.well
|
|
||||||
div.row.text-info.bg-info
|
|
||||||
div.col-md-2
|
|
||||||
span.easy Easy
|
|
||||||
span :
|
|
||||||
div.col-md-10
|
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.easy.sessionID}")
|
|
||||||
span Play #{teamID} vs
|
|
||||||
strong= challengers.easy.opponentName
|
|
||||||
span #{otherTeamID}
|
|
||||||
|
|
||||||
if challengers.medium
|
|
||||||
.well
|
|
||||||
div.row.text-warning.bg-warning
|
|
||||||
div.col-md-2
|
|
||||||
span.medium Medium
|
|
||||||
span :
|
|
||||||
div.col-md-10
|
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.medium.sessionID}")
|
|
||||||
span Play #{teamID} vs
|
|
||||||
strong= challengers.medium.opponentName
|
|
||||||
span #{otherTeamID}
|
|
||||||
|
|
||||||
if challengers.hard
|
|
||||||
.well
|
|
||||||
div.row.text-danger.bg-danger
|
|
||||||
div.col-md-2
|
|
||||||
span.hard Hard
|
|
||||||
span :
|
|
||||||
div.col-md-10
|
|
||||||
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.hard.sessionID}")
|
|
||||||
span Play #{teamID} vs
|
|
||||||
strong= challengers.hard.opponentName
|
|
||||||
span #{otherTeamID}
|
|
|
@ -11,6 +11,10 @@ module.exports = class HomeView extends View
|
||||||
events:
|
events:
|
||||||
'mouseover #beginner-campaign': 'onMouseOverButton'
|
'mouseover #beginner-campaign': 'onMouseOverButton'
|
||||||
'mouseout #beginner-campaign': 'onMouseOutButton'
|
'mouseout #beginner-campaign': 'onMouseOutButton'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super(arguments...)
|
||||||
|
ThangType.loadUniversalWizard()
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
|
|
|
@ -24,14 +24,17 @@ module.exports = class LadderView extends CocoView
|
||||||
super(options)
|
super(options)
|
||||||
@teams = teamDataFromLevel @level
|
@teams = teamDataFromLevel @level
|
||||||
@leaderboards = {}
|
@leaderboards = {}
|
||||||
|
@refreshLadder()
|
||||||
|
|
||||||
|
refreshLadder: ->
|
||||||
for team in @teams
|
for team in @teams
|
||||||
|
@leaderboards[team.id]?.off 'sync'
|
||||||
# teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
|
# teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
|
||||||
teamSession = null
|
teamSession = null
|
||||||
# console.log "Team session: #{JSON.stringify teamSession}"
|
# console.log "Team session: #{JSON.stringify teamSession}"
|
||||||
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession)
|
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession)
|
||||||
@leaderboards[team.id].once 'sync', @onLeaderboardLoaded, @
|
@leaderboards[team.id].once 'sync', @onLeaderboardLoaded, @
|
||||||
|
|
||||||
onChallengersLoaded: -> @renderMaybe()
|
|
||||||
onLeaderboardLoaded: -> @renderMaybe()
|
onLeaderboardLoaded: -> @renderMaybe()
|
||||||
|
|
||||||
renderMaybe: ->
|
renderMaybe: ->
|
||||||
|
@ -48,7 +51,7 @@ module.exports = class LadderView extends CocoView
|
||||||
team.leaderboard = @leaderboards[team.id] for team in @teams
|
team.leaderboard = @leaderboards[team.id] for team in @teams
|
||||||
ctx.levelID = @levelID
|
ctx.levelID = @levelID
|
||||||
ctx
|
ctx
|
||||||
|
|
||||||
class LeaderboardData
|
class LeaderboardData
|
||||||
constructor: (@level, @team, @session) ->
|
constructor: (@level, @team, @session) ->
|
||||||
_.extend @, Backbone.Events
|
_.extend @, Backbone.Events
|
||||||
|
|
|
@ -14,6 +14,9 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
|
|
||||||
constructor: (options, @level, @sessions) ->
|
constructor: (options, @level, @sessions) ->
|
||||||
super(options)
|
super(options)
|
||||||
|
@refreshMatches()
|
||||||
|
|
||||||
|
refreshMatches: ->
|
||||||
@teams = teamDataFromLevel @level
|
@teams = teamDataFromLevel @level
|
||||||
@nameMap = {}
|
@nameMap = {}
|
||||||
@loadNames()
|
@loadNames()
|
||||||
|
@ -82,6 +85,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
c1 and not _.isEqual(c1, c2)
|
c1 and not _.isEqual(c1, c2)
|
||||||
|
|
||||||
rankSession: (e) ->
|
rankSession: (e) ->
|
||||||
|
console.log "Clicked"
|
||||||
button = $(e.target).closest('.rank-button')
|
button = $(e.target).closest('.rank-button')
|
||||||
sessionID = button.data('session-id')
|
sessionID = button.data('session-id')
|
||||||
session = _.find @sessions.models, { id: sessionID }
|
session = _.find @sessions.models, { id: sessionID }
|
||||||
|
|
|
@ -3,19 +3,20 @@ template = require 'templates/play/ladder/play_modal'
|
||||||
ThangType = require 'models/ThangType'
|
ThangType = require 'models/ThangType'
|
||||||
{me} = require 'lib/auth'
|
{me} = require 'lib/auth'
|
||||||
LeaderboardCollection = require 'collections/LeaderboardCollection'
|
LeaderboardCollection = require 'collections/LeaderboardCollection'
|
||||||
|
{teamDataFromLevel} = require './utils'
|
||||||
|
|
||||||
module.exports = class LadderPlayModal extends View
|
module.exports = class LadderPlayModal extends View
|
||||||
id: "ladder-play-modal"
|
id: "ladder-play-modal"
|
||||||
template: template
|
template: template
|
||||||
closeButton: true
|
closeButton: true
|
||||||
startsLoading = true
|
startsLoading: true
|
||||||
|
|
||||||
constructor: (options, @level, @session, @team) ->
|
constructor: (options, @level, @session, @team) ->
|
||||||
super(options)
|
super(options)
|
||||||
@nameMap = {}
|
@nameMap = {}
|
||||||
@otherTeam = if team is 'ogres' then 'humans' else 'ogres'
|
@otherTeam = if team is 'ogres' then 'humans' else 'ogres'
|
||||||
@startLoadingChallengersMaybe()
|
@startLoadingChallengersMaybe()
|
||||||
@wizardType = ThangType.wizardType
|
@wizardType = ThangType.loadUniversalWizard()
|
||||||
|
|
||||||
# PART 1: Load challengers from the db unless some are in the matches
|
# PART 1: Load challengers from the db unless some are in the matches
|
||||||
|
|
||||||
|
@ -24,8 +25,8 @@ module.exports = class LadderPlayModal extends View
|
||||||
if matches?.length then @loadNames() else @loadChallengers()
|
if matches?.length then @loadNames() else @loadChallengers()
|
||||||
|
|
||||||
loadChallengers: ->
|
loadChallengers: ->
|
||||||
@challengers = new ChallengersData(@level, @team, @otherTeam, @session)
|
@challengersCollection = new ChallengersData(@level, @team, @otherTeam, @session)
|
||||||
@challengers.on 'sync', @loadNames, @
|
@challengersCollection.on 'sync', @loadNames, @
|
||||||
|
|
||||||
# PART 2: Loading the names of the other users
|
# PART 2: Loading the names of the other users
|
||||||
|
|
||||||
|
@ -35,11 +36,12 @@ module.exports = class LadderPlayModal extends View
|
||||||
|
|
||||||
success = (@nameMap) =>
|
success = (@nameMap) =>
|
||||||
for challenger in _.values(@challengers)
|
for challenger in _.values(@challengers)
|
||||||
challenger.opponentName = @nameMap[challenger.opponentID] or 'Anoner'
|
challenger.opponentName = @nameMap[challenger.opponentID]?.name or 'Anoner'
|
||||||
|
challenger.opponentWizard = @nameMap[challenger.opponentID]?.wizard or {}
|
||||||
@checkWizardLoaded()
|
@checkWizardLoaded()
|
||||||
|
|
||||||
$.ajax('/db/user/-/names', {
|
$.ajax('/db/user/-/names', {
|
||||||
data: {ids: ids}
|
data: {ids: ids, wizard: true}
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
success: success
|
success: success
|
||||||
})
|
})
|
||||||
|
@ -62,8 +64,27 @@ module.exports = class LadderPlayModal extends View
|
||||||
ctx.teamName = _.string.titleize @team
|
ctx.teamName = _.string.titleize @team
|
||||||
ctx.teamID = @team
|
ctx.teamID = @team
|
||||||
ctx.otherTeamID = @otherTeam
|
ctx.otherTeamID = @otherTeam
|
||||||
ctx.challengers = if not @startsLoading then @challengers else {}
|
|
||||||
ctx.portraitSRC = @wizardType.getPortraitSource()
|
teamsList = teamDataFromLevel @level
|
||||||
|
teams = {}
|
||||||
|
teams[team.id] = team for team in teamsList
|
||||||
|
ctx.teamColor = teams[@team].primaryColor
|
||||||
|
ctx.teamBackgroundColor = teams[@team].bgColor
|
||||||
|
ctx.opponentTeamColor = teams[@otherTeam].primaryColor
|
||||||
|
ctx.opponentTeamBackgroundColor = teams[@otherTeam].bgColor
|
||||||
|
|
||||||
|
ctx.challengers = @challengers or {}
|
||||||
|
for challenger in _.values ctx.challengers
|
||||||
|
continue unless challenger and @wizardType.loaded
|
||||||
|
if (not challenger.opponentImageSource) and challenger.opponentWizard?.colorConfig
|
||||||
|
challenger.opponentImageSource = @wizardType.getPortraitSource(
|
||||||
|
{colorConfig: challenger.opponentWizard.colorConfig})
|
||||||
|
|
||||||
|
if @wizardType.loaded
|
||||||
|
ctx.genericPortrait = @wizardType.getPortraitSource()
|
||||||
|
myColorConfig = me.get('wizard')?.colorConfig
|
||||||
|
ctx.myPortrait = if myColorConfig then @wizardType.getPortraitSource({colorConfig: myColorConfig}) else ctx.genericPortrait
|
||||||
|
|
||||||
ctx.myName = me.get('name') || 'Newcomer'
|
ctx.myName = me.get('name') || 'Newcomer'
|
||||||
ctx
|
ctx
|
||||||
|
|
||||||
|
@ -72,10 +93,10 @@ module.exports = class LadderPlayModal extends View
|
||||||
getChallengers: ->
|
getChallengers: ->
|
||||||
# make an object of challengers to everything needed to link to them
|
# make an object of challengers to everything needed to link to them
|
||||||
challengers = {}
|
challengers = {}
|
||||||
if @challengers
|
if @challengersCollection
|
||||||
easyInfo = @challengeInfoFromSession(@challengers.easyPlayer.models[0])
|
easyInfo = @challengeInfoFromSession(@challengersCollection.easyPlayer.models[0])
|
||||||
mediumInfo = @challengeInfoFromSession(@challengers.mediumPlayer.models[0])
|
mediumInfo = @challengeInfoFromSession(@challengersCollection.mediumPlayer.models[0])
|
||||||
hardInfo = @challengeInfoFromSession(@challengers.hardPlayer.models[0])
|
hardInfo = @challengeInfoFromSession(@challengersCollection.hardPlayer.models[0])
|
||||||
else
|
else
|
||||||
matches = @session.get('matches')
|
matches = @session.get('matches')
|
||||||
won = (m for m in matches when m.metrics.rank < m.opponents[0].metrics.rank)
|
won = (m for m in matches when m.metrics.rank < m.opponents[0].metrics.rank)
|
||||||
|
@ -127,10 +148,8 @@ class ChallengersData
|
||||||
@hardPlayer = new LeaderboardCollection(@level, {order:-1, scoreOffset: score + 5, limit: 1, team: @otherTeam})
|
@hardPlayer = new LeaderboardCollection(@level, {order:-1, scoreOffset: score + 5, limit: 1, team: @otherTeam})
|
||||||
@hardPlayer.fetch()
|
@hardPlayer.fetch()
|
||||||
@hardPlayer.once 'sync', @challengerLoaded, @
|
@hardPlayer.once 'sync', @challengerLoaded, @
|
||||||
console.log 'fetching challengers yes'
|
|
||||||
|
|
||||||
challengerLoaded: ->
|
challengerLoaded: ->
|
||||||
console.log 'challenger loaded'
|
|
||||||
if @allLoaded()
|
if @allLoaded()
|
||||||
@loaded = true
|
@loaded = true
|
||||||
@trigger 'sync'
|
@trigger 'sync'
|
||||||
|
|
|
@ -1,195 +0,0 @@
|
||||||
RootView = require 'views/kinds/RootView'
|
|
||||||
Level = require 'models/Level'
|
|
||||||
LevelSession = require 'models/LevelSession'
|
|
||||||
LeaderboardCollection = require 'collections/LeaderboardCollection'
|
|
||||||
|
|
||||||
module.exports = class LadderTeamView extends RootView
|
|
||||||
id: 'ladder-team-view'
|
|
||||||
template: require 'templates/play/ladder/team'
|
|
||||||
startsLoading: true
|
|
||||||
|
|
||||||
events:
|
|
||||||
'click #rank-button': 'rankSession'
|
|
||||||
|
|
||||||
# PART 1: Loading Level/Session
|
|
||||||
|
|
||||||
constructor: (options, @levelID, @team) ->
|
|
||||||
super(options)
|
|
||||||
@otherTeam = if team is 'ogres' then 'humans' else 'ogres'
|
|
||||||
@level = new Level(_id:@levelID)
|
|
||||||
@level.fetch()
|
|
||||||
@level.once 'sync', @onLevelLoaded, @
|
|
||||||
|
|
||||||
url = "/db/level/#{@levelID}/session?team=#{@team}"
|
|
||||||
@session = new LevelSession()
|
|
||||||
@session.url = -> url
|
|
||||||
@session.fetch()
|
|
||||||
@session.once 'sync', @onSessionLoaded, @
|
|
||||||
|
|
||||||
onLevelLoaded: -> @startLoadingChallengersMaybe()
|
|
||||||
onSessionLoaded: -> @startLoadingChallengersMaybe()
|
|
||||||
|
|
||||||
# PART 2: Loading some challengers if we don't have any matches yet
|
|
||||||
|
|
||||||
startLoadingChallengersMaybe: ->
|
|
||||||
return unless @level.loaded and @session.loaded
|
|
||||||
matches = @session.get('matches')
|
|
||||||
if matches?.length then @loadNames() else @loadChallengers()
|
|
||||||
|
|
||||||
loadChallengers: ->
|
|
||||||
@challengers = new ChallengersData(@level, @team, @otherTeam, @session)
|
|
||||||
@challengers.on 'sync', @loadNames, @
|
|
||||||
|
|
||||||
# PART 3: Loading the names of the other users
|
|
||||||
|
|
||||||
loadNames: ->
|
|
||||||
ids = []
|
|
||||||
ids.push match.opponents[0].userID for match in @session.get('matches') or []
|
|
||||||
ids = ids.concat(@challengers.playerIDs()) if @challengers
|
|
||||||
|
|
||||||
success = (@nameMap) =>
|
|
||||||
for match in @session.get('matches') or []
|
|
||||||
opponent = match.opponents[0]
|
|
||||||
opponent.userName = @nameMap[opponent.userID]
|
|
||||||
@finishRendering()
|
|
||||||
|
|
||||||
$.ajax('/db/user/-/names', {
|
|
||||||
data: {ids: ids}
|
|
||||||
type: 'POST'
|
|
||||||
success: success
|
|
||||||
})
|
|
||||||
|
|
||||||
# PART 4: Rendering
|
|
||||||
|
|
||||||
finishRendering: ->
|
|
||||||
@startsLoading = false
|
|
||||||
@render()
|
|
||||||
|
|
||||||
getRenderData: ->
|
|
||||||
ctx = super()
|
|
||||||
ctx.level = @level
|
|
||||||
ctx.levelID = @levelID
|
|
||||||
ctx.teamName = _.string.titleize @team
|
|
||||||
ctx.teamID = @team
|
|
||||||
ctx.otherTeamID = @otherTeam
|
|
||||||
ctx.challengers = if not @startsLoading then @getChallengers() else {}
|
|
||||||
ctx.readyToRank = @readyToRank()
|
|
||||||
|
|
||||||
convertMatch = (match) =>
|
|
||||||
opponent = match.opponents[0]
|
|
||||||
state = 'win'
|
|
||||||
state = 'loss' if match.metrics.rank > opponent.metrics.rank
|
|
||||||
state = 'tie' if match.metrics.rank is opponent.metrics.rank
|
|
||||||
{
|
|
||||||
state: state
|
|
||||||
opponentName: @nameMap[opponent.userID]
|
|
||||||
opponentID: opponent.userID
|
|
||||||
when: moment(match.date).fromNow()
|
|
||||||
sessionID: opponent.sessionID
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.matches = (convertMatch(match) for match in @session.get('matches') or [])
|
|
||||||
ctx.matches.reverse()
|
|
||||||
ctx.score = (@session.get('totalScore') or 10).toFixed(2)
|
|
||||||
ctx
|
|
||||||
|
|
||||||
afterRender: ->
|
|
||||||
super()
|
|
||||||
@setRankingButtonText(if @readyToRank() then 'rank' else 'unavailable')
|
|
||||||
|
|
||||||
readyToRank: ->
|
|
||||||
c1 = @session.get('code')
|
|
||||||
c2 = @session.get('submittedCode')
|
|
||||||
c1 and not _.isEqual(c1, c2)
|
|
||||||
|
|
||||||
getChallengers: ->
|
|
||||||
# make an object of challengers to everything needed to link to them
|
|
||||||
challengers = {}
|
|
||||||
if @challengers
|
|
||||||
easyInfo = @challengeInfoFromSession(@challengers.easyPlayer.models[0])
|
|
||||||
mediumInfo = @challengeInfoFromSession(@challengers.mediumPlayer.models[0])
|
|
||||||
hardInfo = @challengeInfoFromSession(@challengers.hardPlayer.models[0])
|
|
||||||
else
|
|
||||||
matches = @session.get('matches')
|
|
||||||
won = (m for m in matches when m.metrics.rank < m.opponents[0].metrics.rank)
|
|
||||||
lost = (m for m in matches when m.metrics.rank > m.opponents[0].metrics.rank)
|
|
||||||
tied = (m for m in matches when m.metrics.rank is m.opponents[0].metrics.rank)
|
|
||||||
easyInfo = @challengeInfoFromMatches(won)
|
|
||||||
mediumInfo = @challengeInfoFromMatches(tied)
|
|
||||||
hardInfo = @challengeInfoFromMatches(lost)
|
|
||||||
@addChallenger easyInfo, challengers, 'easy'
|
|
||||||
@addChallenger mediumInfo, challengers, 'medium'
|
|
||||||
@addChallenger hardInfo, challengers, 'hard'
|
|
||||||
challengers
|
|
||||||
|
|
||||||
addChallenger: (info, challengers, title) ->
|
|
||||||
# check for duplicates first
|
|
||||||
return unless info
|
|
||||||
for key, value of challengers
|
|
||||||
return if value.sessionID is info.sessionID
|
|
||||||
challengers[title] = info
|
|
||||||
|
|
||||||
challengeInfoFromSession: (session) ->
|
|
||||||
# given a model from the db, return info needed for a link to the match
|
|
||||||
return unless session
|
|
||||||
return {
|
|
||||||
sessionID: session.id
|
|
||||||
opponentName: @nameMap[session.get('creator')] or 'Anoner'
|
|
||||||
opponentID: session.get('creator')
|
|
||||||
}
|
|
||||||
|
|
||||||
challengeInfoFromMatches: (matches) ->
|
|
||||||
return unless matches?.length
|
|
||||||
match = _.sample matches
|
|
||||||
opponent = match.opponents[0]
|
|
||||||
return {
|
|
||||||
sessionID: opponent.sessionID
|
|
||||||
opponentName: opponent.userName or 'Anoner'
|
|
||||||
opponentID: opponent.userID
|
|
||||||
}
|
|
||||||
|
|
||||||
rankSession: ->
|
|
||||||
return unless @readyToRank()
|
|
||||||
@setRankingButtonText('ranking')
|
|
||||||
|
|
||||||
success = => @setRankingButtonText('ranked')
|
|
||||||
failure = => @setRankingButtonText('failed')
|
|
||||||
|
|
||||||
$.ajax '/queue/scoring', {
|
|
||||||
type: 'POST'
|
|
||||||
data: { session: @session.id }
|
|
||||||
success: success
|
|
||||||
failure: failure
|
|
||||||
}
|
|
||||||
|
|
||||||
setRankingButtonText: (spanClass) ->
|
|
||||||
rankButton = $('#rank-button')
|
|
||||||
rankButton.find('span').addClass('hidden')
|
|
||||||
rankButton.find(".#{spanClass}").removeClass('hidden')
|
|
||||||
rankButton.toggleClass 'disabled', spanClass isnt 'rank'
|
|
||||||
|
|
||||||
class ChallengersData
|
|
||||||
constructor: (@level, @team, @otherTeam, @session) ->
|
|
||||||
_.extend @, Backbone.Events
|
|
||||||
score = @session?.get('totalScore') or 25
|
|
||||||
@easyPlayer = new LeaderboardCollection(@level, {order:1, scoreOffset: score - 5, limit: 1, team: @otherTeam})
|
|
||||||
@easyPlayer.fetch()
|
|
||||||
@easyPlayer.once 'sync', @challengerLoaded, @
|
|
||||||
@mediumPlayer = new LeaderboardCollection(@level, {order:1, scoreOffset: score, limit: 1, team: @otherTeam})
|
|
||||||
@mediumPlayer.fetch()
|
|
||||||
@mediumPlayer.once 'sync', @challengerLoaded, @
|
|
||||||
@hardPlayer = new LeaderboardCollection(@level, {order:-1, scoreOffset: score + 5, limit: 1, team: @otherTeam})
|
|
||||||
@hardPlayer.fetch()
|
|
||||||
@hardPlayer.once 'sync', @challengerLoaded, @
|
|
||||||
|
|
||||||
challengerLoaded: ->
|
|
||||||
if @allLoaded()
|
|
||||||
@loaded = true
|
|
||||||
@trigger 'sync'
|
|
||||||
|
|
||||||
playerIDs: ->
|
|
||||||
collections = [@easyPlayer, @mediumPlayer, @hardPlayer]
|
|
||||||
(c.models[0].get('creator') for c in collections when c?.models[0])
|
|
||||||
|
|
||||||
allLoaded: ->
|
|
||||||
_.all [@easyPlayer.loaded, @mediumPlayer.loaded, @hardPlayer.loaded]
|
|
|
@ -64,6 +64,16 @@ module.exports = class LadderView extends RootView
|
||||||
return if @startsLoading
|
return if @startsLoading
|
||||||
@insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions))
|
@insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions))
|
||||||
@insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions))
|
@insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions))
|
||||||
|
setInterval(@fetchSessionsAndRefreshViews.bind(@), 10000)
|
||||||
|
|
||||||
|
fetchSessionsAndRefreshViews: ->
|
||||||
|
@sessions.fetch({"success": @refreshViews})
|
||||||
|
|
||||||
|
refreshViews: =>
|
||||||
|
@ladderTab.refreshLadder()
|
||||||
|
@myMatchesTab.refreshMatches()
|
||||||
|
console.log "refreshed views!"
|
||||||
|
|
||||||
|
|
||||||
# Simulations
|
# Simulations
|
||||||
|
|
||||||
|
@ -105,4 +115,4 @@ module.exports = class LadderView extends RootView
|
||||||
teamID = button.data('team')
|
teamID = button.data('team')
|
||||||
session = (s for s in @sessions.models when s.get('team') is teamID)[0]
|
session = (s for s in @sessions.models when s.get('team') is teamID)[0]
|
||||||
modal = new LadderPlayModal({}, @level, session, teamID)
|
modal = new LadderPlayModal({}, @level, session, teamID)
|
||||||
@openModalView modal
|
@openModalView modal
|
||||||
|
|
|
@ -114,11 +114,19 @@ UserHandler = class UserHandler extends Handler
|
||||||
ids = ids.split(',') if _.isString ids
|
ids = ids.split(',') if _.isString ids
|
||||||
ids = _.uniq ids
|
ids = _.uniq ids
|
||||||
|
|
||||||
|
# TODO: Extend and repurpose this handler to return other public info about a user more flexibly,
|
||||||
|
# say by a query parameter that lists public properties to return.
|
||||||
|
returnWizard = req.query.wizard or req.body.wizard
|
||||||
|
query = if returnWizard then {name:1, wizard:1} else {name:1}
|
||||||
|
|
||||||
makeFunc = (id) ->
|
makeFunc = (id) ->
|
||||||
(callback) ->
|
(callback) ->
|
||||||
User.findById(id, {name:1}).exec (err, document) ->
|
User.findById(id, query).exec (err, document) ->
|
||||||
return done(err) if err
|
return done(err) if err
|
||||||
callback(null, document?.get('name') or '')
|
if document and returnWizard
|
||||||
|
callback(null, {name:document.get('name'), wizard:document.get('wizard') or {}})
|
||||||
|
else
|
||||||
|
callback(null, document?.get('name') or '')
|
||||||
|
|
||||||
funcs = {}
|
funcs = {}
|
||||||
for id in ids
|
for id in ids
|
||||||
|
|
Reference in a new issue