From 22e80f6d24737b6ee19674deb7c43e6bf037a2f7 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Mon, 3 Mar 2014 09:03:44 -0800 Subject: [PATCH] Set up a play modal, starting to refactor wizard thang type loading to be shared across the site. --- app/models/ThangType.coffee | 7 ++ app/styles/play/ladder/play_modal.sass | 108 +++++++++++++++++ app/templates/play/ladder.jade | 2 +- app/templates/play/ladder/play_modal.jade | 64 ++++++++++ app/views/home_view.coffee | 10 +- app/views/play/ladder/play_modal.coffee | 140 ++++++++++++++++++++++ app/views/play/ladder_view.coffee | 11 +- 7 files changed, 333 insertions(+), 9 deletions(-) create mode 100644 app/styles/play/ladder/play_modal.sass create mode 100644 app/templates/play/ladder/play_modal.jade create mode 100644 app/views/play/ladder/play_modal.coffee diff --git a/app/models/ThangType.coffee b/app/models/ThangType.coffee index 6aaff80a5..c162f9287 100644 --- a/app/models/ThangType.coffee +++ b/app/models/ThangType.coffee @@ -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 \ No newline at end of file diff --git a/app/styles/play/ladder/play_modal.sass b/app/styles/play/ladder/play_modal.sass new file mode 100644 index 000000000..8dc69a5ae --- /dev/null +++ b/app/styles/play/ladder/play_modal.sass @@ -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 \ No newline at end of file diff --git a/app/templates/play/ladder.jade b/app/templates/play/ladder.jade index 4d056ce97..18802f55d 100644 --- a/app/templates/play/ladder.jade +++ b/app/templates/play/ladder.jade @@ -20,7 +20,7 @@ block content div.column.col-md-2 for team in teams div.column.col-md-4 - a(href="/play/ladder/#{levelID}/team/#{team.id}", style="background-color: #{team.primaryColor}").play-button.btn.btn-danger.btn-block.btn-lg + 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 div.column.col-md-2 diff --git a/app/templates/play/ladder/play_modal.jade b/app/templates/play/ladder/play_modal.jade new file mode 100644 index 000000000..6eae0c87c --- /dev/null +++ b/app/templates/play/ladder/play_modal.jade @@ -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 \ No newline at end of file diff --git a/app/views/home_view.coffee b/app/views/home_view.coffee index 7289b4ca9..a16c1a9ba 100644 --- a/app/views/home_view.coffee +++ b/app/views/home_view.coffee @@ -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() diff --git a/app/views/play/ladder/play_modal.coffee b/app/views/play/ladder/play_modal.coffee new file mode 100644 index 000000000..560397d37 --- /dev/null +++ b/app/views/play/ladder/play_modal.coffee @@ -0,0 +1,140 @@ +View = require 'views/kinds/ModalView' +template = require 'templates/play/ladder/play_modal' +ThangType = require 'models/ThangType' +{me} = require 'lib/auth' + +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, @ + + 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] diff --git a/app/views/play/ladder_view.coffee b/app/views/play/ladder_view.coffee index 25d15f484..b1d74b182 100644 --- a/app/views/play/ladder_view.coffee +++ b/app/views/play/ladder_view.coffee @@ -3,10 +3,11 @@ Level = require 'models/Level' Simulator = require 'lib/simulator/Simulator' LevelSession = require 'models/LevelSession' CocoCollection = require 'models/CocoCollection' -LeaderboardCollection = require 'collections/LeaderboardCollection' {teamDataFromLevel} = require './ladder/utils' + LadderTabView = require './ladder/ladder_tab' MyMatchesTabView = require './ladder/my_matches_tab' +LadderPlayModal = require './ladder/play_modal' HIGHEST_SCORE = 1000000 @@ -26,6 +27,7 @@ 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) @@ -97,3 +99,10 @@ module.exports = class LadderView extends RootView catch e console.log "There was a problem with the named simulation status: #{e}" $("#simulation-status-text").text @simulationStatus + + 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 \ No newline at end of file