Merge pull request from codecombat/master

Merge ladder view into production
This commit is contained in:
Michael Schmatz 2014-03-03 09:54:22 -08:00
commit ae4366bdb1
14 changed files with 721 additions and 212 deletions

View file

@ -210,3 +210,10 @@ module.exports = class ThangType extends CocoModel
onFileUploaded: =>
console.log 'Image uploaded'
wizOriginal = "52a00d55cf1818f2be00000b"
url = "/db/thang_type/#{wizOriginal}/version"
wizardType = new module.exports()
wizardType.url = -> url
wizardType.fetch()
module.exports.wizardType = wizardType

View file

@ -1,4 +1,10 @@
#ladder-view
h1
text-align: center
.tab-pane
margin-top: 10px
.score-cell
width: 50px
@ -10,10 +16,6 @@
width: 45%
margin: 0 2.5%
#simulation-status-text
display: inline
margin-left: 10px
.name-col-cell
max-width: 300px
text-overflow: ellipsis

View file

@ -0,0 +1,108 @@
#ladder-play-modal
.tutorial-suggestion
text-align: center
font-size: 18px
.play-option
margin-bottom: 15px
width: 100%
height: 100px
overflow: hidden
background: white
border: 1px solid #333
position: relative
-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.4
border-radius: 5px
.play-option:hover
opacity: 1
.my-icon
position: relative
left: 0
top: -10px
.opponent-icon
position: relative
float: right
right: 0
top: -10px
-moz-transform: scaleX(-1)
-o-transform: scaleX(-1)
-webkit-transform: scaleX(-1)
transform: scaleX(-1)
filter: FlipH
-ms-filter: "FlipH"
.name-label
border-bottom: 20px solid lightslategray
height: 0
width: 40%
position: absolute
bottom: 0
color: black
font-weight: bold
text-align: center
span
position: relative
top: 1px
.my-name
border-right: 15px solid transparent
left: 0
span
left: 3px
.opponent-name
border-left: 15px solid transparent
right: 0
//text-align: right
span
right: 3px
.difficulty
border-top: 25px solid darkgray
border-left: 20px solid transparent
border-right: 20px solid transparent
height: 0
width: 30%
position: absolute
left: 35%
top: 0
color: black
text-align: center
font-size: 18px
font-weight: bold
span
position: relative
top: -25px
.easy-option .difficulty
border-top: 25px solid limegreen
.medium-option .difficulty
border-top: 25px solid darkorange
.hard-option .difficulty
border-top: 25px solid black
color: white
.vs
position: absolute
left: 40%
right: 40%
text-align: center
top: 35px
font-size: 40px
font-weight: bolder
color: black

View file

@ -2,17 +2,11 @@ extends /templates/base
block content
div#level-column
h3= level.get('name')
div#level-description
!{description}
if !me.get('anonymous')
//a(href="http://www.youtube.com/watch?v=IFvfZiJGDsw&list=HL1392928835&feature=mh_lolz").intro-button.btn.btn-primary.btn-lg Watch the Video
a(href="/play/level/brawlwood-tutorial").intro-button.btn.btn-primary.btn-lg Play the Tutorial
h1= level.get('name')
//if !me.get('anonymous')
// a(href="/play/level/brawlwood-tutorial").intro-button.btn.btn-primary.btn-lg Play the Tutorial
hr
if me.get('anonymous')
div#must-log-in
p
@ -23,41 +17,37 @@ block content
else
div#columns.row
div.column.col-md-2
for team in teams
div.column.col-md-6
a(href="/play/ladder/#{levelID}/team/#{team.id}", style="background-color: #{team.primaryColor}").play-button.btn.btn-danger.btn-block.btn-lg
div.column.col-md-4
a(style="background-color: #{team.primaryColor}", data-team=team.id).play-button.btn.btn-danger.btn-block.btn-lg
span Play As
span= team.name
table.table.table-bordered.table-condensed.table-hover
//(style="background-color: #{team.bgColor}")
tr
th(colspan=3, style="color: #{team.primaryColor}")
span= team.name
span Leaderboard
tr
th Score
th.name-col-cell Name
th
for session in team.leaderboard.topPlayers.models
- var myRow = session.get('creator') == me.id
tr(class=myRow ? "success" : "")
td.score-cell= session.get('totalScore').toFixed(2)
td.name-col-cell= session.get('creatorName') || "Anonymous"
td
if(!myRow)
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") Battle as #{team.otherTeam}!
else
a(href="/play/ladder/#{levelID}/team/#{team.id}") View your #{team.id} matches.
unless me.attributes.anonymous
hr
button.btn.btn-warning.btn-lg.highlight#simulate-button(style="margin-bottom:10px;") Simulate Games!
p(id="simulation-status-text", style="display:inline; margin-left:10px;")
if simulationStatus
| #{simulationStatus}
else
| By simulating games you can get your game ranked faster!
if me.isAdmin()
button.btn.btn-danger.btn-lg.highlight#simulate-all-button(style="margin-bottom:10px; float: right;") RESET AND SIMULATE GAMES
div.column.col-md-2
hr
ul.nav.nav-pills
li.active
a(href="#ladder", data-toggle="tab") Ladder
li
a(href="#my-matches", data-toggle="tab") My Matches
li
a(href="#simulate", data-toggle="tab") Simulate
div.tab-content
.tab-pane.active.well#ladder
#ladder-tab-view
.tab-pane.well#my-matches
#my-matches-tab-view
.tab-pane.well#simulate
p(id="simulation-status-text")
if simulationStatus
| #{simulationStatus}
else
| By simulating games you can get your game ranked faster!
p
button.btn.btn-warning.btn-lg.highlight#simulate-button() Simulate Games!
if me.isAdmin()
p
button.btn.btn-danger.btn-lg.highlight#simulate-all-button() RESET AND SIMULATE GAMES

View file

@ -0,0 +1,23 @@
div#columns.row
for team in teams
div.column.col-md-6
table.table.table-bordered.table-condensed.table-hover
tr
th(colspan=3, style="color: #{team.primaryColor}")
span= team.name
span Leaderboard
tr
th Score
th.name-col-cell Name
th
for session in team.leaderboard.topPlayers.models
- var myRow = session.get('creator') == me.id
tr(class=myRow ? "success" : "")
td.score-cell= session.get('totalScore').toFixed(2)
td.name-col-cell= session.get('creatorName') || "Anonymous"
td
if(!myRow)
a(href="/play/level/#{level.get('slug') || level.id}/?team=#{team.otherTeam}&opponent=#{session.id}") Battle as #{team.otherTeam}!
else
a(href="/play/ladder/#{levelID}/team/#{team.id}") View your #{team.id} matches.

View file

@ -0,0 +1,53 @@
//if matches.length
// p#your-score
// span Your Current Score:
// span
// strong= score
div#columns.row
for team in teams
div.matches-column.col-md-6
table.table.table-bordered.table-condensed
tr
th(colspan=4, style="color: #{team.primaryColor}")
span Your
span
span= team.name
span
span Matches
if team.session
button.btn.btn-sm.btn-warning.pull-right.rank-button(data-session-id=team.session.id)
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
tr
th Result
th Opponent
th When
th
for match in team.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 ' + team.otherTeam
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{match.sessionID}")= text
if !team.matches.length
tr
td(colspan=4).alert.alert-warning
| No ranked matches for this team!
| Play against some competitors and then come back here to get your game ranked.

View file

@ -0,0 +1,64 @@
extends /templates/modal/modal_base
block modal-header-content
h3 Choose an Opponent
block modal-body-content
p.tutorial-suggestion
span Not sure what's going on?
|
a(href="/play/level/brawlwood-tutorial") Play the tutorial first.
a(href="/play/level/#{levelID}?team=#{teamID}")
div.play-option
img(src=portraitSRC).my-icon
img(src=portraitSRC).opponent-icon
div.my-name.name-label
span= myName
div.opponent-name.name-label
span Simple AI
div.difficulty
span Warmup
div.vs VS
if challengers.easy
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.easy.sessionID}")
div.play-option.easy-option
img(src=portraitSRC).my-icon
img(src=portraitSRC).opponent-icon
div.my-name.name-label
span= myName
div.opponent-name.name-label
span= challengers.easy.opponentName
div.difficulty
span Easy
div.vs VS
if challengers.medium
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.medium.sessionID}")
div.play-option.medium-option
img(src=portraitSRC).my-icon
img(src=portraitSRC).opponent-icon
div.my-name.name-label
span= myName
div.opponent-name.name-label
span= challengers.medium.opponentName
div.difficulty
span Medium
div.vs VS
if challengers.hard
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.hard.sessionID}")
div.play-option.hard-option
img(src=portraitSRC).my-icon
img(src=portraitSRC).opponent-icon
div.my-name.name-label
span= myName
div.opponent-name.name-label
span= challengers.hard.opponentName
div.difficulty
span Hard
div.vs VS
block modal-footer

View file

@ -28,12 +28,8 @@ module.exports = class HomeView extends View
@$el.find('.modal').on 'shown.bs.modal', ->
$('input:visible:first', @).focus()
wizOriginal = "52a00d55cf1818f2be00000b"
url = "/db/thang_type/#{wizOriginal}/version"
@wizardType = new ThangType()
@wizardType.url = -> url
@wizardType.fetch()
@wizardType.once 'sync', @initCanvas
@wizardType = ThangType.wizardType
if @wizardType.loaded then @initCanvas else @wizardType.once 'sync', @initCanvas, @
# Try to find latest level and set "Play" link to go to that level
if localStorage?
@ -48,7 +44,7 @@ module.exports = class HomeView extends View
else
console.log("TODO: Insert here code to get latest level played from the database. If this can't be found, we just let the user play the first level.")
initCanvas: =>
initCanvas: ->
@stage = new createjs.Stage($('#beginner-campaign canvas', @$el)[0])
@createWizard()

View file

@ -0,0 +1,97 @@
CocoView = require 'views/kinds/CocoView'
Level = require 'models/Level'
LevelSession = require 'models/LevelSession'
CocoCollection = require 'models/CocoCollection'
LeaderboardCollection = require 'collections/LeaderboardCollection'
{teamDataFromLevel} = require './utils'
HIGHEST_SCORE = 1000000
class LevelSessionsCollection extends CocoCollection
url: ''
model: LevelSession
constructor: (levelID) ->
super()
@url = "/db/level/#{levelID}/all_sessions"
module.exports = class LadderView extends CocoView
id: 'ladder-tab-view'
template: require 'templates/play/ladder/ladder_tab'
startsLoading: true
constructor: (options, @level, @sessions) ->
super(options)
@teams = teamDataFromLevel @level
@leaderboards = {}
for team in @teams
# teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
teamSession = null
# console.log "Team session: #{JSON.stringify teamSession}"
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession)
@leaderboards[team.id].once 'sync', @onLeaderboardLoaded, @
onChallengersLoaded: -> @renderMaybe()
onLeaderboardLoaded: -> @renderMaybe()
renderMaybe: ->
leaderboardModels = _.values(@leaderboards)
return unless _.every leaderboardModels, (loader) -> loader.loaded
@startsLoading = false
@render()
getRenderData: ->
ctx = super()
ctx.level = @level
ctx.link = "/play/level/#{@level.get('name')}"
ctx.teams = @teams
team.leaderboard = @leaderboards[team.id] for team in @teams
ctx.levelID = @levelID
ctx
class LeaderboardData
constructor: (@level, @team, @session) ->
_.extend @, Backbone.Events
@topPlayers = new LeaderboardCollection(@level, {order:-1, scoreOffset: HIGHEST_SCORE, team: @team, limit: if @session then 10 else 20})
@topPlayers.fetch()
@topPlayers.comparator = (model) ->
return -model.get('totalScore')
@topPlayers.sort()
@topPlayers.once 'sync', @leaderboardPartLoaded, @
# if @session
# score = @session.get('totalScore') or 25
# @playersAbove = new LeaderboardCollection(@level, {order:1, scoreOffset: score, limit: 4, team: @team})
# @playersAbove.fetch()
# @playersAbove.once 'sync', @leaderboardPartLoaded, @
# @playersBelow = new LeaderboardCollection(@level, {order:-1, scoreOffset: score, limit: 4, team: @team})
# @playersBelow.fetch()
# @playersBelow.once 'sync', @leaderboardPartLoaded, @
leaderboardPartLoaded: ->
if @session
if @topPlayers.loaded # and @playersAbove.loaded and @playersBelow.loaded
@loaded = true
@fetchNames()
else
@loaded = true
@fetchNames()
fetchNames: ->
sessionCollections = [@topPlayers, @playersAbove, @playersBelow]
sessionCollections = (s for s in sessionCollections when s)
ids = []
for collection in sessionCollections
ids.push model.get('creator') for model in collection.models
success = (nameMap) =>
for collection in sessionCollections
session.set('creatorName', nameMap[session.get('creator')]) for session in collection.models
@trigger 'sync'
$.ajax('/db/user/-/names', {
data: {ids: ids}
type: 'POST'
success: success
})

View file

@ -0,0 +1,104 @@
CocoView = require 'views/kinds/CocoView'
Level = require 'models/Level'
LevelSession = require 'models/LevelSession'
LeaderboardCollection = require 'collections/LeaderboardCollection'
{teamDataFromLevel} = require './utils'
module.exports = class MyMatchesTabView extends CocoView
id: 'my-matches-tab-view'
template: require 'templates/play/ladder/my_matches_tab'
startsLoading: true
events:
'click .rank-button': 'rankSession'
constructor: (options, @level, @sessions) ->
super(options)
@teams = teamDataFromLevel @level
@nameMap = {}
@loadNames()
loadNames: ->
ids = []
for session in @sessions.models
ids.push match.opponents[0].userID for match in session.get('matches') or []
success = (@nameMap) =>
for session in @sessions.models
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
})
finishRendering: ->
@startsLoading = false
@render()
getRenderData: ->
ctx = super()
ctx.level = @level
ctx.levelID = @level.get('slug') or @level.id
ctx.teams = @teams
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
}
for team in @teams
team.session = (s for s in @sessions.models when s.get('team') is team.id)[0]
team.readyToRank = @readyToRank(team.session)
team.matches = (convertMatch(match) for match in team.session?.get('matches') or [])
team.matches.reverse()
team.score = (team.session?.get('totalScore') or 10).toFixed(2)
ctx
afterRender: ->
super()
@$el.find('.rank-button').each (i, el) =>
button = $(el)
sessionID = button.data('session-id')
session = _.find @sessions.models, { id: sessionID }
@setRankingButtonText button, if @readyToRank(session) then 'rank' else 'unavailable'
readyToRank: (session) ->
c1 = session?.get('code')
c2 = session?.get('submittedCode')
c1 and not _.isEqual(c1, c2)
rankSession: (e) ->
button = $(e.target).closest('.rank-button')
sessionID = button.data('session-id')
session = _.find @sessions.models, { id: sessionID }
return unless @readyToRank(session)
@setRankingButtonText(button, 'ranking')
success = => @setRankingButtonText(button, 'ranked')
failure = => @setRankingButtonText(button, 'failed')
$.ajax '/queue/scoring', {
type: 'POST'
data: { session: sessionID }
success: success
failure: failure
}
setRankingButtonText: (rankButton, spanClass) ->
rankButton.find('span').addClass('hidden')
rankButton.find(".#{spanClass}").removeClass('hidden')
rankButton.toggleClass 'disabled', spanClass isnt 'rank'

View file

@ -0,0 +1,143 @@
View = require 'views/kinds/ModalView'
template = require 'templates/play/ladder/play_modal'
ThangType = require 'models/ThangType'
{me} = require 'lib/auth'
LeaderboardCollection = require 'collections/LeaderboardCollection'
module.exports = class LadderPlayModal extends View
id: "ladder-play-modal"
template: template
closeButton: true
startsLoading = true
constructor: (options, @level, @session, @team) ->
super(options)
@nameMap = {}
@otherTeam = if team is 'ogres' then 'humans' else 'ogres'
@startLoadingChallengersMaybe()
@wizardType = ThangType.wizardType
# PART 1: Load challengers from the db unless some are in the matches
startLoadingChallengersMaybe: ->
matches = @session?.get('matches')
if matches?.length then @loadNames() else @loadChallengers()
loadChallengers: ->
@challengers = new ChallengersData(@level, @team, @otherTeam, @session)
@challengers.on 'sync', @loadNames, @
# PART 2: Loading the names of the other users
loadNames: ->
@challengers = @getChallengers()
ids = (challenger.opponentID for challenger in _.values @challengers)
success = (@nameMap) =>
for challenger in _.values(@challengers)
challenger.opponentName = @nameMap[challenger.opponentID] or 'Anoner'
@checkWizardLoaded()
$.ajax('/db/user/-/names', {
data: {ids: ids}
type: 'POST'
success: success
})
# PART 3: Make sure wizard is loaded
checkWizardLoaded: ->
if @wizardType.loaded then @finishRendering() else @wizardType.once 'sync', @finishRendering, @
# PART 4: Render
finishRendering: ->
@startsLoading = false
@render()
getRenderData: ->
ctx = super()
ctx.level = @level
ctx.levelID = @level.get('slug') or @level.id
ctx.teamName = _.string.titleize @team
ctx.teamID = @team
ctx.otherTeamID = @otherTeam
ctx.challengers = if not @startsLoading then @challengers else {}
ctx.portraitSRC = @wizardType.getPortraitSource()
ctx.myName = me.get('name') || 'Newcomer'
ctx
# Choosing challengers
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
opponentID: session.get('creator')
}
challengeInfoFromMatches: (matches) ->
return unless matches?.length
match = _.sample matches
opponent = match.opponents[0]
return {
sessionID: opponent.sessionID
opponentID: opponent.userID
}
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, @
console.log 'fetching challengers yes'
challengerLoaded: ->
console.log 'challenger loaded'
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]

View file

@ -0,0 +1,22 @@
{hslToHex} = require 'lib/utils'
module.exports.teamDataFromLevel = (level) ->
alliedSystem = _.find level.get('systems'), (value) -> value.config?.teams?
teamNames = (teamName for teamName, teamConfig of alliedSystem.config.teams when teamConfig.playable)
teamConfigs = alliedSystem.config.teams
teams = []
for team in teamNames or []
otherTeam = if team is 'ogres' then 'humans' else 'ogres'
color = teamConfigs[team].color
bgColor = hslToHex([color.hue, color.saturation, color.lightness + (1 - color.lightness) * 0.5])
primaryColor = hslToHex([color.hue, 0.5, 0.5])
teams.push({
id: team
name: _.string.titleize(team)
otherTeam: otherTeam
bgColor: bgColor
primaryColor: primaryColor
})
teams

View file

@ -3,8 +3,11 @@ Level = require 'models/Level'
Simulator = require 'lib/simulator/Simulator'
LevelSession = require 'models/LevelSession'
CocoCollection = require 'models/CocoCollection'
LeaderboardCollection = require 'collections/LeaderboardCollection'
{hslToHex} = require 'lib/utils'
{teamDataFromLevel} = require './ladder/utils'
LadderTabView = require './ladder/ladder_tab'
MyMatchesTabView = require './ladder/my_matches_tab'
LadderPlayModal = require './ladder/play_modal'
HIGHEST_SCORE = 1000000
@ -14,7 +17,7 @@ class LevelSessionsCollection extends CocoCollection
constructor: (levelID) ->
super()
@url = "/db/level/#{levelID}/all_sessions"
@url = "/db/level/#{levelID}/my_sessions"
module.exports = class LadderView extends RootView
id: 'ladder-view'
@ -24,9 +27,48 @@ module.exports = class LadderView extends RootView
events:
'click #simulate-button': 'onSimulateButtonClick'
'click #simulate-all-button': 'onSimulateAllButtonClick'
'click .play-button': 'onClickPlayButton'
constructor: (options, @levelID) ->
super(options)
@level = new Level(_id:@levelID)
@level.fetch()
@level.once 'sync', @onLevelLoaded, @
@sessions = new LevelSessionsCollection(levelID)
@sessions.fetch({})
@sessions.once 'sync', @onMySessionsLoaded, @
@simulator = new Simulator()
@simulator.on 'statusUpdate', @updateSimulationStatus, @
@teams = []
onLevelLoaded: -> @renderMaybe()
onMySessionsLoaded: -> @renderMaybe()
renderMaybe: ->
return unless @level.loaded and @sessions.loaded
@teams = teamDataFromLevel @level
@startsLoading = false
@render()
getRenderData: ->
ctx = super()
ctx.level = @level
ctx.link = "/play/level/#{@level.get('name')}"
ctx.simulationStatus = @simulationStatus
ctx.teams = @teams
ctx.levelID = @levelID
ctx
afterRender: ->
super()
return if @startsLoading
@insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions))
@insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions))
# Simulations
onSimulateAllButtonClick: (e) ->
submitIDs = _.pluck @leaderboards[@teams[0]].topPlayers.models, "id"
submitIDs = _.pluck @leaderboards[@teams[0].id].topPlayers.models, "id"
for ID in submitIDs
$.ajax
url: '/queue/scoring'
@ -58,140 +100,9 @@ module.exports = class LadderView extends RootView
console.log "There was a problem with the named simulation status: #{e}"
$("#simulation-status-text").text @simulationStatus
constructor: (options, @levelID) ->
super(options)
@level = new Level(_id:@levelID)
@level.fetch()
@level.once 'sync', @onLevelLoaded, @
@simulator = new Simulator()
@simulator.on 'statusUpdate', @updateSimulationStatus, @
# @sessions = new LevelSessionsCollection(levelID)
# @sessions.fetch({})
# @sessions.once 'sync', @onMySessionsLoaded, @
onLevelLoaded: -> @startLoadingPhaseTwoMaybe()
onMySessionsLoaded: ->
@startLoadingPhaseTwoMaybe()
startLoadingPhaseTwoMaybe: ->
return unless @level.loaded # and @sessions.loaded
@loadPhaseTwo()
loadPhaseTwo: ->
alliedSystem = _.find @level.get('systems'), (value) -> value.config?.teams?
teams = []
for teamName, teamConfig of alliedSystem.config.teams
continue unless teamConfig.playable
teams.push teamName
@teams = teams
@teamConfigs = alliedSystem.config.teams
@leaderboards = {}
@challengers = {}
for team in teams
# teamSession = _.find @sessions.models, (session) -> session.get('team') is team
teamSession = null
console.log "Team session: #{JSON.stringify teamSession}"
@leaderboards[team] = new LeaderboardData(@level, team, teamSession)
@leaderboards[team].once 'sync', @onLeaderboardLoaded, @
onChallengersLoaded: -> @renderMaybe()
onLeaderboardLoaded: -> @renderMaybe()
renderMaybe: ->
loaders = _.values(@leaderboards) # .concat(_.values(@challengers))
return unless _.every loaders, (loader) -> loader.loaded
@startsLoading = false
@render()
getRenderData: ->
ctx = super()
ctx.level = @level
description = @level.get('description')
ctx.description = if description then marked(description) else ''
ctx.link = "/play/level/#{@level.get('name')}"
ctx.simulationStatus = @simulationStatus
ctx.teams = []
ctx.levelID = @levelID
for team in @teams or []
otherTeam = if team is 'ogres' then 'humans' else 'ogres'
color = @teamConfigs[team].color
bgColor = hslToHex([color.hue, color.saturation, color.lightness + (1 - color.lightness) * 0.5])
primaryColor = hslToHex([color.hue, 0.5, 0.5])
ctx.teams.push({
id: team
name: _.string.titleize(team)
leaderboard: @leaderboards[team]
otherTeam: otherTeam
bgColor: bgColor
primaryColor: primaryColor
})
ctx
class LeaderboardData
constructor: (@level, @team, @session) ->
_.extend @, Backbone.Events
@topPlayers = new LeaderboardCollection(@level, {order:-1, scoreOffset: HIGHEST_SCORE, team: @team, limit: if @session then 10 else 20})
@topPlayers.fetch()
@topPlayers.comparator = (model) ->
return -model.get('totalScore')
@topPlayers.sort()
@topPlayers.once 'sync', @leaderboardPartLoaded, @
# if @session
# score = @session.get('totalScore') or 25
# @playersAbove = new LeaderboardCollection(@level, {order:1, scoreOffset: score, limit: 4, team: @team})
# @playersAbove.fetch()
# @playersAbove.once 'sync', @leaderboardPartLoaded, @
# @playersBelow = new LeaderboardCollection(@level, {order:-1, scoreOffset: score, limit: 4, team: @team})
# @playersBelow.fetch()
# @playersBelow.once 'sync', @leaderboardPartLoaded, @
leaderboardPartLoaded: ->
if @session
if @topPlayers.loaded # and @playersAbove.loaded and @playersBelow.loaded
@loaded = true
@fetchNames()
else
@loaded = true
@fetchNames()
fetchNames: ->
sessionCollections = [@topPlayers, @playersAbove, @playersBelow]
sessionCollections = (s for s in sessionCollections when s)
ids = []
for collection in sessionCollections
ids.push model.get('creator') for model in collection.models
success = (nameMap) =>
for collection in sessionCollections
session.set('creatorName', nameMap[session.get('creator')]) for session in collection.models
@trigger 'sync'
$.ajax('/db/user/-/names', {
data: {ids: ids}
type: 'POST'
success: success
})
class ChallengersData
constructor: (@level, @team, @session) ->
_.extend @, Backbone.Events
score = @session?.get('totalScore') or 25
@easyPlayer = new LeaderboardCollection(@level, {order:1, scoreOffset: score - 5, limit: 1, team: @team})
@easyPlayer.fetch()
@easyPlayer.once 'sync', @challengerLoaded, @
@mediumPlayer = new LeaderboardCollection(@level, {order:1, scoreOffset: score, limit: 1, team: @team})
@mediumPlayer.fetch()
@mediumPlayer.once 'sync', @challengerLoaded, @
@hardPlayer = new LeaderboardCollection(@level, {order:-1, scoreOffset: score + 5, limit: 1, team: @team})
@hardPlayer.fetch()
@hardPlayer.once 'sync', @challengerLoaded, @
challengerLoaded: ->
if @easyPlayer.loaded and @mediumPlayer.loaded and @hardPlayer.loaded
@loaded = true
@trigger 'sync'
onClickPlayButton: (e) ->
button = $(e.target).closest('.play-button')
teamID = button.data('team')
session = (s for s in @sessions.models when s.get('team') is teamID)[0]
modal = new LadderPlayModal({}, @level, session, teamID)
@openModalView modal

View file

@ -27,7 +27,7 @@ LevelHandler = class LevelHandler extends Handler
getByRelationship: (req, res, args...) ->
return @getSession(req, res, args[0]) if args[1] is 'session'
return @getLeaderboard(req, res, args[0]) if args[1] is 'leaderboard'
return @getAllSessions(req, res, args[0]) if args[1] is 'all_sessions'
return @getMySessions(req, res, args[0]) if args[1] is 'my_sessions'
return @getFeedback(req, res, args[0]) if args[1] is 'feedback'
return @sendNotFoundError(res)
@ -86,26 +86,15 @@ LevelHandler = class LevelHandler extends Handler
# associated with the handler, because the handler might return a different type
# of model, like in this case. Refactor to move that logic to the model instead.
getAllSessions: (req, res, id) ->
getMySessions: (req, res, id) ->
@fetchLevelByIDAndHandleErrors id, req, res, (err, level) =>
sessionQuery =
level:
original: level.original.toString()
majorVersion: level.version.major
submitted: true
propertiesToReturn = [
'_id'
'totalScore'
'submitted'
'team'
'creatorName'
]
query = Session
.find(sessionQuery)
.select(propertiesToReturn.join ' ')
creator: req.user._id+''
query = Session.find(sessionQuery)
query.exec (err, results) =>
if err then @sendDatabaseError(res, err) else @sendSuccess res, results