Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-11-26 08:53:44 -08:00
commit 8624a82036
33 changed files with 169 additions and 44 deletions

View file

@ -81,3 +81,6 @@ module.exports = class CocoClass
stopListeningToShortcuts: ->
return unless key?
key.deleteScope(@scope)
playSound: (trigger, volume=1) ->
Backbone.Mediator.publish 'audio-player:play-sound', trigger: trigger, volume: volume

View file

@ -249,9 +249,11 @@ module.exports = LevelOptions =
'swift-dagger':
requiredGear: {waist: 'leather-belt', 'programming-book': 'programmaticon-ii', eyes: 'wooden-glasses', 'right-hand': 'crude-crossbow', 'left-hand': 'crude-dagger', wrists: 'sundial-wristwatch'}
restrictedGear: {eyes: 'crude-glasses'}
allowedHeroes: ['ninja', 'trapper', 'forest-archer']
'shrapnel':
requiredGear: {waist: 'leather-belt', 'programming-book': 'programmaticon-ii', eyes: 'wooden-glasses', 'right-hand': 'crude-crossbow', 'left-hand': 'weak-charge', wrists: 'sundial-wristwatch'}
restrictedGear: {eyes: 'crude-glasses', 'left-hand': 'crude-dagger'}
allowedHeroes: ['ninja', 'trapper', 'forest-archer']
# Wizard branch
'arcane-ally':
@ -260,10 +262,12 @@ module.exports = LevelOptions =
'touch-of-death':
requiredGear: {waist: 'leather-belt', 'programming-book': 'programmaticon-ii', eyes: 'wooden-glasses', 'right-hand': 'enchanted-stick', 'left-hand': 'unholy-tome-i', wrists: 'sundial-wristwatch'}
restrictedGear: {}
allowedHeroes: ['librarian', 'potion-master', 'sorcerer']
'bonemender':
requiredGear: {waist: 'leather-belt', 'programming-book': 'programmaticon-ii', eyes: 'wooden-glasses', 'right-hand': 'enchanted-stick', 'left-hand': 'book-of-life-i', wrists: 'sundial-wristwatch'}
restrictedGear: {'left-hand': 'unholy-tome-i'}
requiredCode: ['canCast']
allowedHeroes: ['librarian', 'potion-master', 'sorcerer']
'coinucopia':
requiredGear: {'programming-book': 'programmaticon-i', feet: 'leather-boots', 'programming-book': 'programmaticon-ii', flag: 'basic-flags'}

View file

@ -3,6 +3,12 @@ PlayHeroesModal = require 'views/play/modal/PlayHeroesModal'
InventoryModal = require 'views/game-menu/InventoryModal'
LevelSession = require 'models/LevelSession'
SuperModel = require 'models/SuperModel'
ThangType = require 'models/ThangType'
LevelOptions = require 'lib/LevelOptions'
lastHeroesEarned = me.get('earned')?.heroes ? []
lastHeroesPurchased = me.get('purchased')?.heroes ? []
module.exports = class LevelSetupManager extends CocoClass
@ -46,9 +52,19 @@ module.exports = class LevelSetupManager extends CocoClass
open: ->
firstModal = if @options.hadEverChosenHero then @inventoryModal else @heroesModal
if (not _.isEqual(lastHeroesEarned, me.get('earned')?.heroes ? []) or
not _.isEqual(lastHeroesPurchased, me.get('purchased')?.heroes ? []))
console.log 'Showing hero picker because heroes earned/purchased has changed.'
firstModal = @heroesModal
else if allowedHeroSlugs = LevelOptions[@options.levelID]?.allowedHeroes
unless _.find(allowedHeroSlugs, (slug) -> ThangType.heroes[slug] is me.get('heroConfig')?.thangType)
firstModal = @heroesModal
lastHeroesEarned = me.get('earned')?.heroes ? []
lastHeroesPurchased = me.get('purchased')?.heroes ? []
@options.parent.openModalView(firstModal)
# @inventoryModal.onShown() # replace?
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@playSound 'game-menu-open'
#- Modal events

View file

@ -247,6 +247,7 @@
tome_select_a_thang: "Select Someone for "
tome_available_spells: "Available Spells"
tome_your_skills: "Your Skills"
tome_help: "Help"
tome_current_method: "Current Method"
hud_continue_short: "Continue"
code_saved: "Code Saved"
@ -356,6 +357,7 @@
skills: "Skills"
available_for_purchase: "Available for Purchase"
level_to_unlock: "Level to unlock:"
restricted_to_certain_heroes: "Only certain heroes can play this level."
skill_docs:
writable: "writable" # Hover over "attack" in Your Skills while playing a level to see most of this

View file

@ -341,6 +341,18 @@ $itemSlotGridHeight: 70px
position: relative
width: 60px
&:not(.equipped):not(.restricted):not(.silhouette)
cursor: pointer
&:hover
padding: 0
img
margin: 1px
button
margin-top: -2px
height: 19px
font-size: 12px
img
width: 56px
height: 56px
@ -354,10 +366,27 @@ $itemSlotGridHeight: 70px
font-size: 11px
border-radius: 1px
padding: 0
@include transition(0.1s ease)
.required-level
@include opacity(0)
@include transition(0.6s ease-in)
pointer-events: none
font-size: 14px
text-align: center
width: 100%
bottom: 20px
top: inherit
position: absolute
color: white
&.active
background-color: rgb(81,153,236)
button
background-color: lighten(rgb(89,136,47), 10%)
box-shadow: 1px 1px 4px #333
color: white
//.status-message .should-equip-message
// display: inline
@ -375,7 +404,6 @@ $itemSlotGridHeight: 70px
&.equipped
background-color: #ff5
display: none
cursor: default
//.item-view
// cursor: default
@ -385,7 +413,6 @@ $itemSlotGridHeight: 70px
&.restricted
background-color: rgba(190, 190, 190, 1)
cursor: default
@include filter(contrast(50%) brightness(100%))
//.item-view
@ -394,16 +421,18 @@ $itemSlotGridHeight: 70px
//.status-message .restricted-message
// display: inline
&.locked
cursor: default
//background-color: gray
&.locked:not(:hover)
@include filter(contrast(75%))
&.silhouette
cursor: default
pointer-events: none
@include filter(contrast(25%) brightness(25%))
opacity: 0.5
img
@include filter(contrast(25%) brightness(25%))
opacity: 0.5
&:hover
.required-level
@include opacity(1)
text-shadow: 0 1px 0 black, 1px 0 0 black, 0 -1px 0 black, -1px 0 0 black
//- Hero/Play buttons

View file

@ -107,6 +107,11 @@ $heroCanvasHeight: 265px
.hero-avatar
background-color: goldenrod
&.restricted
@include opacity(0.25)
.hero-avatar
background-color: black
//- Small transformations to jumble the hero icons a little
@ -147,7 +152,7 @@ $heroCanvasHeight: 265px
#hero-carousel
.hero-item
&.locked:not(.purchasable)
&.locked:not(.purchasable), &.restricted
@include opacity(0.6)
canvas, .hero-feature-image
@ -255,7 +260,7 @@ $heroCanvasHeight: 265px
color: #333
text-align: center
#locked-hero-explanation
#locked-hero-explanation, #restricted-hero-explanation
position: absolute
left: 32px
top: 527px

View file

@ -46,6 +46,10 @@
for item in itemGroups.lockedItems.models
.item(class=item.classes, data-item-id=item.id)
img(src=item.getPortraitURL(), draggable="false")
if item.level
.required-level
span(data-i18n="general.player_level")
span.spl= item.level
.clearfix
#item-details-view

View file

@ -13,6 +13,7 @@ if entryGroupSlugs
div(class="properties properties-" + slug + " nano-content")
else
// Hero; group by items, no tabs.
h4(data-i18n="play_level.tome_your_skills")
//h4(data-i18n="play_level.tome_your_skills")
h4(data-i18n="play_level.tome_help")
.properties

View file

@ -12,13 +12,13 @@
.carousel-indicator-container
ol.carousel-indicators
for hero, index in heroes
li(data-hero-id=hero.get('original'), title=hero.name, data-slide-to=index, data-target="#hero-carousel", class="hero-indicator hero-index-" + index + (hero.locked ? " locked" : "") + (hero.purchasable ? " purchasable" : ""))
li(data-hero-id=hero.get('original'), title=hero.name, data-slide-to=index, data-target="#hero-carousel", class="hero-indicator hero-index-" + index + (hero.locked ? " locked" : "") + (hero.purchasable ? " purchasable" : "") + (hero.restricted ? " restricted" : ""))
.hero-avatar
if hero.locked && !hero.purchasable
img.lock-indicator(src="/images/pages/game-menu/lock.png", draggable="false")
.carousel-inner
for hero in heroes
div(class="item hero-item" + (hero.locked ? " locked" : "") + (hero.purchasable ? " purchasable" : ""), data-hero-id=hero.get('original'))
div(class="item hero-item" + (hero.locked ? " locked" : "") + (hero.purchasable ? " purchasable" : "") + (hero.restricted ? " restricted" : ""), data-hero-id=hero.get('original'))
canvas.hero-canvas
.hero-feature-image
img(draggable="false")
@ -28,7 +28,7 @@
.hero-stat-row
.stat-label(data-i18n='choose_hero.status')
.stat-value.hero-status-value(data-i18n=hero.purchasable ? 'play.purchasable' : (hero.locked ? 'play.locked' : 'play.available'))
.stat-value.hero-status-value(data-i18n=hero.restricted ? 'inventory.restricted_title' : (hero.purchasable ? 'play.purchasable' : (hero.locked ? 'play.locked' : 'play.available')))
.hero-stat-row
.stat-label(data-i18n='choose_hero.weapons')
@ -53,7 +53,14 @@
#hero-footer
if visibleHero
if visibleHero.purchasable
if visibleHero.restricted
#restricted-hero-explanation
h2
span= visibleHero.name
span.spl(data-i18n="inventory.restricted_title") Restricted
span.spr(data-i18n="choose_hero.restricted_to_certain_heroes") Only certain heroes can play this level.
else if visibleHero.purchasable
#purchasable-hero-explanation
h2(data-i18n="choose_hero.available_for_purchase") Available for Purchase
button.btn.unlock-button#purchase-hero-button

View file

@ -31,6 +31,7 @@ module.exports = class HomeView extends RootView
c
onClickBeginnerCampaign: (e) ->
@playSound 'menu-button-click'
e.preventDefault()
e.stopImmediatePropagation()
window.tracker?.trackEvent 'Homepage', Action: 'Play'

View file

@ -51,15 +51,15 @@ module.exports = class GameMenuModal extends ModalView
firstView = (@subviews.options_view)
firstView.$el.addClass 'active'
firstView.onShown?()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@playSound 'game-menu-open'
@$el.find('.nano:visible').nanoScroller()
onTabShown: (e) ->
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-tab-switch', volume: 1
@playSound 'game-menu-tab-switch'
@subviews[e.target.hash.substring(1).replace(/-/g, '_')].onShown?()
onHidden: ->
super()
subview.onHidden?() for subviewKey, subview of @subviews
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
@playSound 'game-menu-close'
Backbone.Mediator.publish 'music-player:exit-menu', {}

View file

@ -44,11 +44,11 @@ module.exports = class LevelGuideView extends CocoView
@$el.find('.nav-tabs li:first').addClass('active')
@$el.find('.tab-content .tab-pane:first').addClass('active')
@$el.find('.nav-tabs a').click(@clickTab)
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'guide-open', volume: 1
@playSound 'guide-open'
clickTab: (e) =>
@$el.find('li.active').removeClass('active')
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'guide-tab-switch', volume: 1
@playSound 'guide-tab-switch'
afterInsert: ->
super()

View file

@ -103,6 +103,9 @@ module.exports = class InventoryModal extends ModalView
else
@itemGroups.availableItems.add(item)
# level to unlock
item.level = item.levelRequiredForItem() if item.get('tier')?
onLoaded: ->
# Both items and session have been loaded.
@onItemsLoaded()
@ -205,11 +208,14 @@ module.exports = class InventoryModal extends ModalView
onItemSlotClick: (e) ->
return if @remainingRequiredEquipment?.length # Don't let them select a slot if we need them to first equip some require gear.
@playSound 'menu-button-click'
@selectItemSlot($(e.target).closest('.item-slot'))
onUnequippedItemClick: (e) ->
return if @justDoubleClicked
itemEl = $(e.target).closest('.item')
return if itemEl.hasClass('silhouette')
@playSound 'menu-button-click'
@selectUnequippedItem(itemEl)
onUnequippedItemDoubleClick: (e) ->
@ -224,6 +230,7 @@ module.exports = class InventoryModal extends ModalView
onClickUnequipItemViewed: -> @unequipSelectedItem()
onClickEquipItemButton: (e) ->
@playSound 'menu-button-click'
itemEl = $(e.target).closest('.item')
@selectUnequippedItem(itemEl)
@equipSelectedItem()
@ -403,11 +410,13 @@ module.exports = class InventoryModal extends ModalView
super()
onClickChooseHero: ->
@playSound 'menu-button-click'
@hide()
@trigger 'choose-hero-click'
onClickPlayLevel: (e) ->
return if @$el.find('#play-level-button').prop 'disabled'
@playSound 'menu-button-click'
@showLoading()
ua = navigator.userAgent.toLowerCase()
unless hasGoneFullScreenOnce or (/safari/.test(ua) and not /chrome/.test(ua)) or $(window).height() >= 658 # Min vertical resolution needed at 1366px wide
@ -440,7 +449,7 @@ module.exports = class InventoryModal extends ModalView
else
callback?()
#- TODO: DRY this between PlayItemsModal and InventoryModal
#- TODO: DRY this between PlayItemsModal and InventoryModal and PlayHeroesModal
onUnlockButtonClicked: (e) ->
e.stopPropagation()
@ -448,8 +457,10 @@ module.exports = class InventoryModal extends ModalView
item = @items.get(button.data('item-id'))
affordable = item.affordable
if not affordable
@playSound 'menu-button-click'
@askToBuyGems button
else if button.hasClass('confirm')
@playSound 'menu-button-unlock-end'
purchase = Purchase.makeFor(item)
purchase.save()
@ -475,6 +486,7 @@ module.exports = class InventoryModal extends ModalView
Backbone.Mediator.publish 'store:item-purchased', item: item, itemSlug: item.get('slug')
else
@playSound 'menu-button-unlock-start'
button.addClass('confirm').text($.i18n.t('play.confirm'))
@$el.one 'click', (e) ->
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
@ -496,6 +508,7 @@ module.exports = class InventoryModal extends ModalView
popover?.$tip?.i18n()
onBuyGemsPromptButtonClicked: (e) ->
@playSound 'menu-button-click'
@openModalView new BuyGemsModal()
onClickedSomewhere: (e) ->

View file

@ -137,7 +137,7 @@ module.exports = class MultiplayerView extends CocoView
# console.log 'MultiplayerView found current real-time session', rts
@currentRealTimeSession = new RealTimeModel("multiplayer_level_sessions/#{@levelID}/#{rts.id}")
@currentRealTimeSession.on 'change', @onCurrentRealTimeSessionChanged
# TODO: Is this necessary? Shouldn't everyone already know we joined a game at this point?
Backbone.Mediator.publish 'real-time-multiplayer:joined-game', realTimeSessionID: @currentRealTimeSession.id
@ -162,6 +162,7 @@ module.exports = class MultiplayerView extends CocoView
@render?()
onCreateRealTimeGame: ->
@playSound 'menu-button-click'
s = @realTimeSessions.create {
creator: @session.get('creator')
creatorName: @session.get('creatorName')
@ -173,7 +174,7 @@ module.exports = class MultiplayerView extends CocoView
@currentRealTimeSession.on 'change', @onCurrentRealTimeSessionChanged
# TODO: s.id === @currentRealTimeSession.id ?
players = new RealTimeCollection("multiplayer_level_sessions/#{@levelID}/#{@currentRealTimeSession.id}/players")
players.create
players.create
id: me.id
state: 'coding'
name: @session.get('creatorName')
@ -184,20 +185,21 @@ module.exports = class MultiplayerView extends CocoView
onJoinRealTimeGame: (e) ->
return if @currentRealTimeSession
@playSound 'menu-button-click'
item = @$el.find(e.target).data('item')
@currentRealTimeSession = @realTimeSessions.get(item.id)
@currentRealTimeSession.on 'change', @onCurrentRealTimeSessionChanged
if @realTimeSessionsPlayers[item.id]
# TODO: SpellView updateTeam() should take care of this team swap update in the real-time multiplayer session
creatorID = @currentRealTimeSession.get('creator')
creator = @realTimeSessionsPlayers[item.id].get(creatorID)
creatorTeam = creator.get('team')
myTeam = @session.get('team')
myTeam = @session.get('team')
if myTeam is creatorTeam
myTeam = if creatorTeam is 'humans' then 'ogres' else 'humans'
@realTimeSessionsPlayers[item.id].create
@realTimeSessionsPlayers[item.id].create
id: me.id
state: 'coding'
name: me.get('name')
@ -209,6 +211,7 @@ module.exports = class MultiplayerView extends CocoView
@render()
onLeaveRealTimeGame: (e) ->
@playSound 'menu-button-click'
if @currentRealTimeSession
@currentRealTimeSession.off 'change', @onCurrentRealTimeSessionChanged
@currentRealTimeSession = null

View file

@ -63,6 +63,7 @@ module.exports = class OptionsView extends CocoView
me.set 'volume', volume
@$el.find('#option-volume-value').text (volume * 100).toFixed(0) + '%'
Backbone.Mediator.publish 'level:set-volume', volume: volume
@playSound 'menu-button-click' # Could have another volume-indicating noise
onHidden: ->
if @playerName and @playerName isnt me.get('name')
@ -109,6 +110,7 @@ module.exports = class OptionsView extends CocoView
onEditProfilePhoto: (e) ->
return if window.application.isIPadApp # TODO: have an iPad-native way of uploading a photo, since we don't want to load FilePicker on iPad (memory)
@playSound 'menu-button-click'
photoContainer = @$el.find('.profile-photo')
onSaving = =>
photoContainer.addClass('saving')

View file

@ -19,6 +19,7 @@ module.exports = class SaveLoadView extends CocoView
super()
onSaveGranularityChanged: (e) ->
@playSound 'menu-button-click'
toShow = $(e.target).val()
@$el.find('.save-list, .save-pane').hide()
@$el.find('.save-list.' + toShow + ', .save-pane.' + toShow).show()

View file

@ -341,10 +341,11 @@ module.exports = class CocoView extends Backbone.View
@pointerRadialDistance = -47
@pointerRotation = options.rotation ? Math.atan2(@$el.outerWidth() * 0.5 - targetLeft, targetTop - @$el.outerHeight() * 0.5)
initialScale = Math.max 1, 20 - me.level()
$pointer.css
opacity: 1.0
transition: 'none'
transform: "rotate(#{@pointerRotation}rad) translate(-3px, #{@pointerRadialDistance}px) scale(20)"
transform: "rotate(#{@pointerRotation}rad) translate(-3px, #{@pointerRadialDistance}px) scale(#{initialScale})"
top: targetTop - 50
left: targetLeft - 50
_.defer =>
@ -427,7 +428,7 @@ module.exports = class CocoView extends Backbone.View
d.msRequestFullscreen or
(if d.webkitRequestFullscreen then -> d.webkitRequestFullscreen Element.ALLOW_KEYBOARD_INPUT else null)
req?.call d
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'full-screen-start', volume: 1 if req
@playSound 'full-screen-start' if req
else
nah = document.exitFullscreen or
document.mozCancelFullScreen or
@ -435,9 +436,12 @@ module.exports = class CocoView extends Backbone.View
document.msExitFullscreen or
document.webkitExitFullscreen
nah?.call document
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'full-screen-end', volume: 1 if nah
@playSound 'full-screen-end' if req
return
playSound: (trigger, volume=1) ->
Backbone.Mediator.publish 'audio-player:play-sound', trigger: trigger, volume: volume
mobileRELong = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i
mobileREShort = /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i

View file

@ -50,23 +50,27 @@ module.exports = class AuthModal extends ModalView
_.delay (=> $('input:visible:first', @$el).focus()), 500
onSignupInstead: (e) ->
@playSound 'menu-button-click'
@mode = 'signup'
@previousFormInputs = forms.formToObject @$el
@render()
_.delay application.router.renderLoginButtons, 500
onLoginInstead: (e) ->
@playSound 'menu-button-click'
@mode = 'login'
@previousFormInputs = forms.formToObject @$el
@render()
_.delay application.router.renderLoginButtons, 500
onSubmitForm: (e) ->
@playSound 'menu-button-click'
e.preventDefault()
if @mode is 'login' then @loginAccount() else @createAccount()
false
checkAge: (e) ->
@playSound 'menu-button-click'
$('#signup-button', @$el).prop 'disabled', not $(e.target).prop('checked')
loginAccount: ->
@ -116,6 +120,7 @@ module.exports = class AuthModal extends ModalView
forms.setErrorToProperty @$el, 'name', "That name is taken! How about #{newName}?", true
onGitHubLoginClicked: ->
@playSound 'menu-button-click'
Backbone.Mediator.publish 'auth:log-in-with-github', {}
gplusAuthSteps: [
@ -126,6 +131,7 @@ module.exports = class AuthModal extends ModalView
]
onClickGPlusLogin: ->
@playSound 'menu-button-click'
step.done = false for step in @gplusAuthSteps
handler = application.gplusHandler

View file

@ -27,6 +27,7 @@ module.exports = class ContactModal extends ModalView
'click #contact-submit-button': 'contact'
contact: ->
@playSound 'menu-button-click'
forms.clearFormAlerts @$el
contactMessage = forms.formToObject @$el
res = tv4.validateMultiple contactMessage, contactSchema

View file

@ -28,6 +28,7 @@ module.exports = class RecoverModal extends ModalView
super options
recoverAccount: (e) =>
@playSound 'menu-button-click'
forms.clearFormAlerts(@$el)
email = (forms.formToObject @$el).email
return unless email

View file

@ -48,6 +48,7 @@ module.exports = class LadderSubmissionView extends CocoView
rankSession: (e) ->
return unless @session.readyToRank()
@playSound 'menu-button-click'
@setRankingButtonText 'submitting'
success = =>
@setRankingButtonText 'submitted' unless @destroyed
@ -87,4 +88,5 @@ module.exports = class LadderSubmissionView extends CocoView
transpiledCode
onHelpSimulate: ->
@playSound 'menu-button-click'
$('a[href="#simulate"]').tab('show')

View file

@ -49,6 +49,7 @@ module.exports = class LevelFlagsView extends CocoView
onFlagSelected: (e) ->
return unless @realTime
@playSound 'menu-button-click' if e.color
color = if e.color is @flagColor then null else e.color
@flagColor = color
Backbone.Mediator.publish 'level:flag-color-selected', color: color
@ -57,6 +58,7 @@ module.exports = class LevelFlagsView extends CocoView
onStageMouseDown: (e) ->
return unless @flagColor and @realTime
@playSound 'menu-button-click' # TODO: different flag placement sound?
pos = x: e.worldPos.x, y: e.worldPos.y
delay = if @realTimeFlags then multiplayerFlagDelay else 0
now = @world.dt * @world.frames.length

View file

@ -72,6 +72,7 @@ module.exports = class LevelLoadingView extends CocoView
@$el.find('.start-level-button').removeClass 'secret'
startUnveiling: (e) ->
@playSound 'menu-button-click'
Backbone.Mediator.publish 'level:loading-view-unveiling', {}
_.delay @onClickStartLevel, 1000 # If they never mouse-up for the click (or a modal shows up and interrupts the click), do it anyway.

View file

@ -293,6 +293,7 @@ module.exports = class HeroVictoryModal extends ModalView
levelInfo?.nextLevels?[type] # 'more_practice', 'skip_ahead', 'continue'
onClickContinue: (e) ->
@playSound 'menu-button-click'
nextLevelLink = @continueLevelLink
if me.getBranchingGroup() is 'all-practice' and @morePracticeLevelLink
nextLevelLink = @morePracticeLevelLink
@ -307,6 +308,7 @@ module.exports = class HeroVictoryModal extends ModalView
@$el.find('.next-levels-prompt').show()
onClickNextLevelBranch: (e) ->
@playSound 'menu-button-click'
e.preventDefault()
route = $(e.target).data('href') or "/play/#{@getNextLevelCampaign()}"
application.tracker?.trackEvent 'Branch Selected', level: @level.get('slug'), label: @level.get('slug'), branch: $(e.target).data('branch-key'), branchingGroup: me.getBranchingGroup(), route: route
@ -314,6 +316,7 @@ module.exports = class HeroVictoryModal extends ModalView
Backbone.Mediator.publish 'router:navigate', route: route, viewClass: require('views/play/WorldMapView'), viewArgs: [{supermodel: if @options.hasReceivedMemoryWarning then null else @supermodel}, @getNextLevelCampaign()]
onClickReturnToLadder: (e) ->
@playSound 'menu-button-click'
e.preventDefault()
route = $(e.target).data('href')
# Preserve the supermodel as we navigate back to the ladder.

View file

@ -9,6 +9,7 @@ module.exports = class ReloadLevelModal extends ModalView
'click #restart-level-confirm-button': 'onClickRestart'
onClickRestart: (e) ->
@playSound 'menu-button-click'
if key.shift
Backbone.Mediator.publish 'level:restart', {}
else

View file

@ -83,6 +83,7 @@ module.exports = class ProblemAlertView extends CocoView
@onRemoveClicked()
onRemoveClicked: ->
@playSound 'menu-button-click'
@$el.hide()
onWindowResize: (e) =>

View file

@ -48,6 +48,7 @@ module.exports = class BuyGemsModal extends ModalView
@render()
onClickProductButton: (e) ->
@playSound 'menu-button-click'
productID = $(e.target).closest('button').val()
product = _.find @products, { id: productID }
@ -60,9 +61,9 @@ module.exports = class BuyGemsModal extends ModalView
description: $.t(product.i18n)
amount: product.amount
})
@productBeingPurchased = product
onStripeReceivedToken: (e) ->
@timestampForPurchase = new Date().getTime()
data = {

View file

@ -69,7 +69,7 @@ module.exports = class ItemDetailsView extends CocoView
c.stats = _.values(stats.stats)
_.last(c.stats).isLast = true if c.stats.length
c.props = []
stats.props = stats.props.concat _.keys @spellDocs
stats.props = _.union stats.props, _.keys @spellDocs
codeLanguage = (me.get('aceConfig') ? {}).language or 'python'
for prop in stats.props
doc = @propDocs[prop] ? @spellDocs[prop] ? {}

View file

@ -21,7 +21,7 @@ module.exports = class PlayAccountModal extends ModalView
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@playSound 'game-menu-open'
@accountSettingsView = new AccountSettingsView()
@insertSubView(@accountSettingsView)
@listenTo @accountSettingsView, 'input-changed', @onInputChanged
@ -31,7 +31,7 @@ module.exports = class PlayAccountModal extends ModalView
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
@playSound 'game-menu-close'
onInputChanged: ->
@$el.find('#save-button')

View file

@ -92,8 +92,8 @@ module.exports = class PlayAchievementsModal extends ModalView
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@playSound 'game-menu-open'
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
@playSound 'game-menu-close'

View file

@ -8,6 +8,7 @@ AudioPlayer = require 'lib/AudioPlayer'
utils = require 'lib/utils'
BuyGemsModal = require 'views/play/modal/BuyGemsModal'
Purchase = require 'models/Purchase'
LevelOptions = require 'lib/LevelOptions'
module.exports = class PlayHeroesModal extends ModalView
className: 'modal fade play-modal'
@ -54,6 +55,8 @@ module.exports = class PlayHeroesModal extends ModalView
original = hero.get('original')
hero.locked = not me.ownsHero(original)
hero.purchasable = hero.locked and (original in (me.get('earned')?.heroes ? []))
if @options.levelID and allowedHeroSlugs = LevelOptions[@options.levelID]?.allowedHeroes
hero.restricted = not (hero.get('slug') in allowedHeroSlugs)
hero.class = (hero.get('heroClass') or 'warrior').toLowerCase()
hero.stats = hero.getHeroStats()
@ -225,9 +228,10 @@ module.exports = class PlayHeroesModal extends ModalView
button = $(e.target).closest('button')
affordable = @visibleHero.get('gems') <= me.gems()
if not affordable
@playSound 'menu-button-click'
@askToBuyGems button
else if button.hasClass('confirm')
@playSound 'menu-button-unlock-end'
purchase = Purchase.makeFor(@visibleHero)
purchase.save()
@ -246,6 +250,7 @@ module.exports = class PlayHeroesModal extends ModalView
Backbone.Mediator.publish 'store:hero-purchased', hero: @visibleHero, heroSlug: @visibleHero.get('slug')
else
@playSound 'menu-button-unlock-start'
button.addClass('confirm').text($.i18n.t('play.confirm'))
@$el.one 'click', (e) ->
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
@ -267,6 +272,7 @@ module.exports = class PlayHeroesModal extends ModalView
popover?.$tip?.i18n()
onBuyGemsPromptButtonClicked: (e) ->
@playSound 'menu-button-click'
@openModalView new BuyGemsModal()
onClickedSomewhere: (e) ->

View file

@ -127,6 +127,7 @@ module.exports = class PlayItemsModal extends ModalView
onItemClicked: (e) ->
return if $(e.target).closest('.unlock-button').length
@playSound 'menu-button-click'
itemEl = $(e.target).closest('.item')
wasSelected = itemEl.hasClass('selected')
@$el.find('.item.selected').removeClass('selected')
@ -141,6 +142,7 @@ module.exports = class PlayItemsModal extends ModalView
@itemDetailsView.setItem(item)
onTabClicked: (e) ->
@playSound 'game-menu-tab-switch'
$($(e.target).attr('href')).find('.nano').nanoScroller({alwaysVisible: true})
onUnlockButtonClicked: (e) ->
@ -149,9 +151,10 @@ module.exports = class PlayItemsModal extends ModalView
item = @idToItem[button.data('item-id')]
affordable = item.affordable
if not affordable
@playSound 'menu-button-click'
@askToBuyGems button
else if button.hasClass('confirm')
@playSound 'menu-button-unlock-end'
purchase = Purchase.makeFor(item)
purchase.save()
@ -169,6 +172,7 @@ module.exports = class PlayItemsModal extends ModalView
Backbone.Mediator.publish 'store:item-purchased', item: item, itemSlug: item.get('slug')
else
@playSound 'menu-button-unlock-start'
button.addClass('confirm').text($.i18n.t('play.confirm'))
@$el.one 'click', (e) ->
button.removeClass('confirm').text($.i18n.t('play.unlock')) if e.target isnt button[0]
@ -189,6 +193,7 @@ module.exports = class PlayItemsModal extends ModalView
popover?.$tip?.i18n()
onBuyGemsPromptButtonClicked: (e) ->
@playSound 'menu-button-click'
@openModalView new BuyGemsModal()
onClickedSomewhere: (e) ->

View file

@ -21,8 +21,8 @@ module.exports = class PlaySettingsModal extends ModalView
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@playSound 'game-menu-open'
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
@playSound 'game-menu-close'