mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 17:02:18 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
0a615fc24e
28 changed files with 190 additions and 61 deletions
|
@ -614,7 +614,9 @@ module.exports = Lank = class Lank extends CocoClass
|
|||
setDebug: (debug) ->
|
||||
return unless @thang?.collides and @options.camera?
|
||||
@addMark 'debug', @options.floatingLayer if debug
|
||||
@marks.debug?.toggle debug
|
||||
if d = @marks.debug
|
||||
d.toggle debug
|
||||
d.updatePosition()
|
||||
|
||||
addLabel: (name, style) ->
|
||||
@labels[name] ?= new Label sprite: @, camera: @options.camera, layer: @options.textLayer, style: style
|
||||
|
|
|
@ -121,6 +121,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
@container.regY = e.surfaceViewport.y
|
||||
if @transformStyle is LayerAdapter.TRANSFORM_SURFACE_TEXT
|
||||
for child in @container.children
|
||||
continue if child.skipScaling
|
||||
child.scaleX *= change
|
||||
child.scaleY *= change
|
||||
|
||||
|
@ -130,6 +131,7 @@ module.exports = LayerAdapter = class LayerAdapter extends CocoClass
|
|||
@container.addChild children...
|
||||
if @transformStyle is LayerAdapter.TRANSFORM_SURFACE_TEXT
|
||||
for child in children
|
||||
continue if child.skipScaling
|
||||
child.scaleX /= @container.scaleX
|
||||
child.scaleY /= @container.scaleY
|
||||
|
||||
|
|
|
@ -34,12 +34,13 @@ module.exports = class Mark extends CocoClass
|
|||
|
||||
onLayerMadeSpriteSheet: ->
|
||||
return unless @sprite
|
||||
return @update() if @markLank
|
||||
# need to update the mark display object manually...
|
||||
# rebuild sprite for new sprite sheet
|
||||
@sprite = null
|
||||
@build()
|
||||
@layer.addChild @sprite
|
||||
@layer.updateLayerOrder()
|
||||
# @updatePosition()
|
||||
@update()
|
||||
|
||||
toggle: (to) ->
|
||||
to = !!to
|
||||
|
|
|
@ -29,6 +29,6 @@ module.exports = class PointChooser extends CocoClass
|
|||
|
||||
updateShape: ->
|
||||
sup = @options.camera.worldToSurface @point
|
||||
@options.surfaceLayer.addChild @shape
|
||||
@options.surfaceLayer.addChild @shape unless @shape.parent
|
||||
@shape.x = sup.x
|
||||
@shape.y = sup.y
|
||||
|
|
|
@ -59,10 +59,11 @@ module.exports = class RegionChooser extends CocoClass
|
|||
|
||||
updateShape: ->
|
||||
rect = @options.camera.normalizeBounds([@firstPoint, @secondPoint])
|
||||
@options.normalStage.removeChild @shape if @shape
|
||||
@options.surfaceLayer.removeChild @shape if @shape
|
||||
@shape = new createjs.Shape()
|
||||
@shape.alpha = 0.5
|
||||
@shape.mouseEnabled = false
|
||||
@shape.graphics.beginFill('#fedcba').drawRect rect.x, rect.y, rect.width, rect.height
|
||||
@shape.graphics.endFill()
|
||||
@options.normalStage.addChild(@shape)
|
||||
@shape.skipScaling = true
|
||||
@options.surfaceLayer.addChild(@shape)
|
||||
|
|
|
@ -135,7 +135,7 @@ module.exports = Surface = class Surface extends CocoClass
|
|||
@coordinateDisplay ?= new CoordinateDisplay camera: @camera, layer: @surfaceTextLayer if showCoordinates
|
||||
|
||||
hookUpChooseControls: ->
|
||||
chooserOptions = stage: @normalStage, normalStage: @normalStage, camera: @camera, restrictRatio: @options.choosing is 'ratio-region'
|
||||
chooserOptions = stage: @webGLStage, surfaceLayer: @surfaceTextLayer, camera: @camera, restrictRatio: @options.choosing is 'ratio-region'
|
||||
klass = if @options.choosing is 'point' then PointChooser else RegionChooser
|
||||
@chooser = new klass chooserOptions
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
|
||||
checkForInitialUserCodeProblems: ->
|
||||
# There might have been some user code problems reported before the goal manager started listening.
|
||||
return unless @world
|
||||
for thang in @world.thangs when thang.isProgrammable
|
||||
for message, problem of thang.publishedUserCodeProblems
|
||||
@onUserCodeProblem {thang: thang, problem: problem}, 0
|
||||
|
|
|
@ -109,6 +109,7 @@ class CocoModel extends Backbone.Model
|
|||
console.debug "Validation failed for #{@constructor.className}: '#{@get('name') or @}'."
|
||||
for error in errors
|
||||
console.debug "\t", error.dataPath, ':', error.message
|
||||
console.trace()
|
||||
return errors
|
||||
|
||||
save: (attrs, options) ->
|
||||
|
@ -285,6 +286,7 @@ class CocoModel extends Backbone.Model
|
|||
if schema.items and _.isArray data
|
||||
sum += @populateI18N(value, schema.items, path+'/'+index) for value, index in data
|
||||
|
||||
@updateI18NCoverage()
|
||||
sum
|
||||
|
||||
@getReferencedModel: (data, schema) ->
|
||||
|
@ -333,6 +335,30 @@ class CocoModel extends Backbone.Model
|
|||
error: ->
|
||||
console.error 'Miserably failed to fetch unnotified achievements', arguments
|
||||
|
||||
CocoModel.pollAchievements = _.debounce CocoModel.pollAchievements, 500
|
||||
CocoModel.pollAchievements = _.debounce CocoModel.pollAchievements, 500
|
||||
|
||||
|
||||
#- Internationalization
|
||||
|
||||
updateI18NCoverage: ->
|
||||
i18nObjects = @findI18NObjects()
|
||||
console.log 'i18n objects', i18nObjects
|
||||
langCodeArrays = (_.keys(i18n) for i18n in i18nObjects)
|
||||
console.log 'lang code arrays', langCodeArrays
|
||||
window.codes = langCodeArrays
|
||||
@set('i18nCoverage', _.intersection(langCodeArrays...))
|
||||
|
||||
findI18NObjects: (data, results) ->
|
||||
data ?= @attributes
|
||||
results ?= []
|
||||
|
||||
if _.isPlainObject(data) or _.isArray(data)
|
||||
for [key, value] in _.pairs data
|
||||
if key is 'i18n'
|
||||
results.push value
|
||||
else if _.isPlainObject(value) or _.isArray(value)
|
||||
@findI18NObjects(value, results)
|
||||
|
||||
return results
|
||||
|
||||
module.exports = CocoModel
|
||||
|
|
|
@ -256,6 +256,7 @@ c.extendSearchableProperties LevelSchema
|
|||
c.extendVersionedProperties LevelSchema, 'level'
|
||||
c.extendPermissionsProperties LevelSchema, 'level'
|
||||
c.extendPatchableProperties LevelSchema
|
||||
c.extendTranslationCoverageProperties LevelSchema
|
||||
|
||||
module.exports = LevelSchema
|
||||
|
||||
|
|
|
@ -143,6 +143,10 @@ me.getLanguageCodeArray = ->
|
|||
return Language.languageCodes
|
||||
|
||||
me.getLanguagesObject = -> return Language
|
||||
|
||||
me.extendTranslationCoverageProperties = (schema) ->
|
||||
schema.properties = {} unless schema.properties?
|
||||
schema.properties.i18nCoverage = { title: 'i18n Coverage', type: 'array', items: { type: 'string' }}
|
||||
|
||||
# OTHER
|
||||
|
||||
|
|
|
@ -139,6 +139,10 @@ $stashWidth: $totalWidth - $equippedWidth - $stashMargin
|
|||
&[data-slot="right-hand"] .placeholder
|
||||
background-position: (-17 * $itemSlotInnerWidth) 0px
|
||||
|
||||
&[data-slot="flag"] .placeholder
|
||||
//background-position: (-18 * $itemSlotInnerWidth) 0px
|
||||
background-position: (-2 * $itemSlotInnerWidth) 0px
|
||||
|
||||
.item-container
|
||||
position: absolute
|
||||
left: 0
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
#victory-header
|
||||
display: block
|
||||
margin: 15px auto 0
|
||||
@include transition(0.25s ease-in)
|
||||
// http://easings.net/#easeOutBack plus tweaked a bit: http://cubic-bezier.com/#.18,.68,.75,2
|
||||
@include transition(0.5s cubic-bezier(0.18, 0.68, 0.75, 2))
|
||||
|
||||
&.out
|
||||
margin-top: -100px
|
||||
@include scale(0)
|
||||
|
||||
.modal-header
|
||||
height: 85px
|
||||
|
@ -95,10 +96,10 @@
|
|||
@include scale(1.5)
|
||||
z-index: 2
|
||||
|
||||
.reward-text
|
||||
font-size: 18px
|
||||
overflow: visible
|
||||
bottom: 9px
|
||||
&.numerical &.animating .reward-text
|
||||
font-size: 18px
|
||||
overflow: visible
|
||||
bottom: 9px
|
||||
|
||||
.reward-image-container
|
||||
top: 8px
|
||||
|
@ -113,6 +114,13 @@
|
|||
&.show
|
||||
@include scale(1)
|
||||
|
||||
&.pending-reward-image
|
||||
img
|
||||
-webkit-filter: brightness(2000%) contrast(25%)
|
||||
-moz-filter: brightness(2000%) contrast(25%)
|
||||
-o-filter: brightness(2000%) contrast(25%)
|
||||
filter: brightness(2000%) contrast(25%)
|
||||
|
||||
img
|
||||
margin: 0
|
||||
position: absolute
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
left: 10px
|
||||
right: 10px
|
||||
background: transparent
|
||||
border: 0
|
||||
border: 1px solid transparent
|
||||
padding: 0
|
||||
text-shadow: none
|
||||
color: white
|
||||
|
@ -31,14 +31,14 @@
|
|||
&:hover, &:focus
|
||||
@include opacity(1)
|
||||
|
||||
.problem-hint
|
||||
.problem-subtitle
|
||||
font-size: 80%
|
||||
|
||||
|
||||
//&.alert-error
|
||||
|
||||
&.alert-warning
|
||||
border-image-source: url(/images/level/code_editor_warning_background.png)
|
||||
|
||||
|
||||
&.alert-info
|
||||
border-image-source: url(/images/level/code_editor_info_background.png)
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
.replace-me(data-item-id=equipment[slot].get('original'))
|
||||
|
||||
.item-slot-column.pull-left
|
||||
for slot in ['minion', 'torso', 'gloves', 'left-hand', 'misc-0']
|
||||
// TODO: add in 'misc-0' again somehow? Used to be where 'flag' is now.
|
||||
for slot in ['minion', 'torso', 'gloves', 'left-hand', 'flag']
|
||||
.item-slot(data-slot=slot)
|
||||
.placeholder
|
||||
.item-container
|
||||
|
|
|
@ -5,6 +5,11 @@ block modal-header-content
|
|||
h3
|
||||
span(data-i18n="general.version_history_for") Version History for:
|
||||
|"#{dataList[0].name}"
|
||||
p
|
||||
|Select two changes below to see the difference.
|
||||
|
||||
div.delta-container
|
||||
div.delta-view
|
||||
|
||||
block modal-body-content
|
||||
if dataList
|
||||
|
@ -25,7 +30,4 @@ block modal-body-content
|
|||
td= data.creator
|
||||
td #{data.commitMessage}
|
||||
|
||||
div.delta-container
|
||||
div.delta-view
|
||||
|
||||
block modal-footer-content
|
|
@ -15,31 +15,31 @@ block modal-body-content
|
|||
- var worth = achievement.get('worth', true);
|
||||
if worth
|
||||
.reward-panel.numerical.xp(data-number=worth, data-number-unit='xp')
|
||||
.reward-image-container(class=animate?'':'show')
|
||||
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
|
||||
img(src="/images/pages/play/level/modal/reward_icon_xp.png")
|
||||
.reward-text= animate ? '+0' : '+'+worth
|
||||
|
||||
if rewards.gems
|
||||
.reward-panel.numerical.gems(data-number=rewards.gems, data-number-unit='gem')
|
||||
.reward-image-container(class=animate?'':'show')
|
||||
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
|
||||
img(src="/images/pages/play/level/modal/reward_icon_gems.png")
|
||||
.reward-text= animate ? '+0' : '+'+rewards.gems
|
||||
|
||||
if rewards.heroes
|
||||
for hero in rewards.heroes
|
||||
- var hero = thangTypes[hero];
|
||||
.reward-panel.hero
|
||||
.reward-image-container(class=animate?'':'show')
|
||||
.reward-panel.hero(data-hero-thang-type=hero.get('original'))
|
||||
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
|
||||
img(src=hero.getPortraitURL())
|
||||
.reward-text= hero.get('name')
|
||||
.reward-text= animate ? 'New Hero' : hero.get('name')
|
||||
|
||||
if rewards.items
|
||||
for item in rewards.items
|
||||
- var item = thangTypes[item];
|
||||
.reward-panel.item
|
||||
.reward-image-container(class=animate?'':'show')
|
||||
.reward-panel.item(data-item-thang-type=item.get('original'))
|
||||
.reward-image-container(class=animate ? 'pending-reward-image' : 'show')
|
||||
img(src=item.getPortraitURL())
|
||||
.reward-text= item.get('name')
|
||||
.reward-text= animate ? 'New Item' : item.get('name')
|
||||
|
||||
|
||||
block modal-footer-content
|
||||
|
@ -60,7 +60,7 @@ block modal-footer-content
|
|||
a.btn.btn-success.world-map-button.hide#continue-button(href="/play-hero", data-dismiss="modal", data-i18n="play_level.victory_play_continue") Continue
|
||||
|
||||
if me.get('anonymous')
|
||||
p.sign-up-poke
|
||||
p.sign-up-poke.hide
|
||||
button.btn.btn-success.sign-up-button.btn-large(data-toggle="coco-modal", data-target="modal/SignupModal", data-i18n="play_level.victory_sign_up") Sign Up to Save Progress
|
||||
span(data-i18n="play_level.victory_sign_up_poke") Want to save your code? Create a free account!
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
button.close(type="button", data-dismiss="alert") ×
|
||||
span.problem-message!= message
|
||||
if hint
|
||||
span.problem-title!= hint
|
||||
br
|
||||
span.problem-hint!= hint
|
||||
span.problem-subtitle!= message
|
||||
else
|
||||
span.problem-title!= message
|
||||
|
|
|
@ -370,7 +370,7 @@ module.exports = class ThangsTabView extends CocoView
|
|||
@adjustThangPos @addThangLank, thang, pos
|
||||
else
|
||||
@addThangLank = null
|
||||
@surface.lankBoss.reallyStopMoving = false
|
||||
@surface?.lankBoss.reallyStopMoving = false
|
||||
|
||||
createEssentialComponents: (defaultComponents) ->
|
||||
physicalConfig = {pos: {x: 10, y: 10, z: 1}}
|
||||
|
|
|
@ -10,7 +10,7 @@ module.exports = class InventoryView extends CocoView
|
|||
id: 'inventory-view'
|
||||
className: 'tab-pane'
|
||||
template: template
|
||||
slots: ['head', 'eyes', 'neck', 'torso', 'wrists', 'gloves', 'left-ring', 'right-ring', 'right-hand', 'left-hand', 'waist', 'feet', 'programming-book', 'pet', 'minion', 'misc-0', 'misc-1']
|
||||
slots: ['head', 'eyes', 'neck', 'torso', 'wrists', 'gloves', 'left-ring', 'right-ring', 'right-hand', 'left-hand', 'waist', 'feet', 'programming-book', 'pet', 'minion', 'flag'] #, 'misc-0', 'misc-1'] # TODO: bring in misc slot(s) again when we have space
|
||||
|
||||
events:
|
||||
'click .item-slot': 'onItemSlotClick'
|
||||
|
|
|
@ -7,6 +7,7 @@ LocalMongo = require 'lib/LocalMongo'
|
|||
utils = require 'lib/utils'
|
||||
ThangType = require 'models/ThangType'
|
||||
LadderSubmissionView = require 'views/play/common/LadderSubmissionView'
|
||||
AudioPlayer = require 'lib/AudioPlayer'
|
||||
|
||||
module.exports = class HeroVictoryModal extends ModalView
|
||||
id: 'hero-victory-modal'
|
||||
|
@ -45,7 +46,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
for thangTypeOriginal in thangTypeOriginals
|
||||
thangType = new ThangType()
|
||||
thangType.url = "/db/thang.type/#{thangTypeOriginal}/version"
|
||||
thangType.project = ['original', 'rasterIcon', 'name']
|
||||
thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers']
|
||||
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
|
||||
|
||||
if achievementIDs.length
|
||||
|
@ -86,7 +87,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
## achievement.completedAWhileAgo = index > 1
|
||||
# achievement.completed = true
|
||||
# achievement.completedAWhileAgo = false
|
||||
# achievement.attributes.worth = (index + 1) * achievement.get('worth')
|
||||
# achievement.attributes.worth = (index + 1) * achievement.get('worth', true)
|
||||
# rewards = achievement.get('rewards')
|
||||
# rewards.gems *= (index + 1)
|
||||
|
||||
|
@ -99,10 +100,14 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
@playSelectionSound hero, true for original, hero of @thangTypes # Preload them
|
||||
@$el.addClass 'with-sign-up' if me.get('anonymous')
|
||||
@updateSavingProgressStatus()
|
||||
@$el.find('#victory-header').delay(250).queue(-> $(@).removeClass('out').dequeue())
|
||||
complete = _.once(_.bind(@beginAnimateNumbers, @))
|
||||
@$el.find('#victory-header').delay(250).queue(->
|
||||
$(@).removeClass('out').dequeue()
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'victory-title-appear' # TODO: actually add this
|
||||
)
|
||||
complete = _.once(_.bind(@beginSequentialAnimations, @))
|
||||
@animatedPanels = $()
|
||||
panels = @$el.find('.achievement-panel')
|
||||
for panel in panels
|
||||
|
@ -126,29 +131,34 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
|
||||
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
||||
|
||||
beginAnimateNumbers: ->
|
||||
@numericalItemPanels = _.map(@animatedPanels.find('.numerical'), (panel) -> {
|
||||
beginSequentialAnimations: ->
|
||||
@sequentialAnimatedPanels = _.map(@animatedPanels.find('.reward-panel'), (panel) -> {
|
||||
number: $(panel).data('number')
|
||||
textEl: $(panel).find('.reward-text')
|
||||
rootEl: $(panel)
|
||||
unit: $(panel).data('number-unit')
|
||||
hero: $(panel).data('hero-thang-type')
|
||||
item: $(panel).data('item-thang-type')
|
||||
})
|
||||
|
||||
@totalXP = 0
|
||||
@totalXP += panel.number for panel in @numericalItemPanels when panel.unit is 'xp'
|
||||
@totalXP += panel.number for panel in @sequentialAnimatedPanels when panel.unit is 'xp'
|
||||
@totalGems = 0
|
||||
@totalGems += panel.number for panel in @numericalItemPanels when panel.unit is 'gem'
|
||||
@totalGems += panel.number for panel in @sequentialAnimatedPanels when panel.unit is 'gem'
|
||||
@gemEl = $('#gem-total')
|
||||
@XPEl = $('#xp-total')
|
||||
@totalXPAnimated = @totalGemsAnimated = @lastTotalXP = @lastTotalGems = 0
|
||||
@numberAnimationStart = new Date()
|
||||
@numberAnimationInterval = setInterval(@tickNumberAnimation, 1000 / 60)
|
||||
@sequentialAnimationStart = new Date()
|
||||
@sequentialAnimationInterval = setInterval(@tickSequentialAnimation, 1000 / 60)
|
||||
|
||||
tickNumberAnimation: =>
|
||||
tickSequentialAnimation: =>
|
||||
# TODO: make sure the animation pulses happen when the numbers go up and sounds play (up to a max speed)
|
||||
return @endAnimateNumbers() unless panel = @numericalItemPanels[0]
|
||||
duration = Math.log(panel.number + 1) / Math.LN10 * 1000 # Math.log10 is ES6
|
||||
ratio = @getEaseRatio (new Date() - @numberAnimationStart), duration
|
||||
return @endSequentialAnimations() unless panel = @sequentialAnimatedPanels[0]
|
||||
if panel.number
|
||||
duration = Math.log(panel.number + 1) / Math.LN10 * 1000 # Math.log10 is ES6
|
||||
else
|
||||
duration = 1000
|
||||
ratio = @getEaseRatio (new Date() - @sequentialAnimationStart), duration
|
||||
if panel.unit is 'xp'
|
||||
newXP = Math.floor(ratio * panel.number)
|
||||
totalXP = @totalXPAnimated + newXP
|
||||
|
@ -158,7 +168,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
xpTrigger = 'xp-' + (totalXP % 6) # 6 xp sounds
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: xpTrigger, volume: 0.5 + ratio / 2
|
||||
@lastTotalXP = totalXP
|
||||
else
|
||||
else if panel.unit is 'gem'
|
||||
newGems = Math.floor(ratio * panel.number)
|
||||
totalGems = @totalGemsAnimated + newGems
|
||||
if totalGems isnt @lastTotalGems
|
||||
|
@ -167,16 +177,24 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
gemTrigger = 'gem-' + (parseInt(panel.number * ratio) % 4) # 4 gem sounds
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: gemTrigger, volume: 0.5 + ratio / 2
|
||||
@lastTotalGems = totalGems
|
||||
else if panel.item
|
||||
thangType = @thangTypes[panel.item]
|
||||
panel.textEl.text(thangType.get('name'))
|
||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'item-unlocked', volume: 1 if 0.5 < ratio < 0.6
|
||||
else if panel.hero
|
||||
thangType = @thangTypes[panel.hero]
|
||||
panel.textEl.text(thangType.get('name'))
|
||||
@playSelectionSound hero if 0.5 < ratio < 0.6
|
||||
if ratio is 1
|
||||
panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse')
|
||||
@numberAnimationStart = new Date()
|
||||
@sequentialAnimationStart = new Date()
|
||||
if panel.unit is 'xp'
|
||||
@totalXPAnimated += panel.number
|
||||
else
|
||||
else if panel.unit is 'gem'
|
||||
@totalGemsAnimated += panel.number
|
||||
@numericalItemPanels.shift()
|
||||
@sequentialAnimatedPanels.shift()
|
||||
return
|
||||
panel.rootEl.addClass('animating').find('.reward-image-container img').addClass('pulse')
|
||||
panel.rootEl.addClass('animating').find('.reward-image-container').removeClass('pending-reward-image').find('img').addClass('pulse')
|
||||
|
||||
getEaseRatio: (timeSinceStart, duration) ->
|
||||
# Ease in/out quadratic - http://gizma.com/easing/
|
||||
|
@ -187,8 +205,8 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
--t
|
||||
-0.5 * (t * (t - 2) - 1)
|
||||
|
||||
endAnimateNumbers: ->
|
||||
clearInterval @numberAnimationInterval
|
||||
endSequentialAnimations: ->
|
||||
clearInterval @sequentialAnimationInterval
|
||||
@animationComplete = true
|
||||
@updateSavingProgressStatus()
|
||||
|
||||
|
@ -196,14 +214,23 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
return unless @animationComplete
|
||||
@$el.find('#saving-progress-label').toggleClass('hide', @readyToContinue)
|
||||
@$el.find('#continue-button').toggleClass('hide', not @readyToContinue)
|
||||
@$el.find('.sign-up-poke').toggleClass('hide', not @readyToContinue)
|
||||
|
||||
onGameSubmitted: (e) ->
|
||||
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
|
||||
Backbone.Mediator.publish 'router:navigate', route: ladderURL
|
||||
|
||||
playSelectionSound: (hero, preload=false) ->
|
||||
return unless sounds = hero.get('soundTriggers')?.selected
|
||||
return unless sound = sounds[Math.floor Math.random() * sounds.length]
|
||||
name = AudioPlayer.nameForSoundReference sound
|
||||
if preload
|
||||
AudioPlayer.preloadSoundReference sound
|
||||
else
|
||||
AudioPlayer.playSound name, 1
|
||||
|
||||
# TODO: award heroes/items and play an awesome sound when you get one
|
||||
|
||||
destroy: ->
|
||||
clearInterval @numberAnimationInterval
|
||||
clearInterval @sequentialAnimationInterval
|
||||
super()
|
||||
|
|
|
@ -15,7 +15,7 @@ module.exports = class PlayItemsModal extends ModalView
|
|||
hands: ['right-hand', 'left-hand']
|
||||
accessories: ['eyes', 'neck', 'left-ring', 'right-ring', 'waist']
|
||||
minions: ['minion', 'pet']
|
||||
misc: ['programming-book', 'misc-0', 'misc-1']
|
||||
misc: ['programming-book', 'flag', 'misc-0', 'misc-1']
|
||||
|
||||
#events:
|
||||
# 'change input.select': 'onSelectionChanged'
|
||||
|
|
|
@ -83,9 +83,11 @@ module.exports = class PlayLevelModal extends ModalView
|
|||
aceConfig.language = codeLanguage
|
||||
me.set 'aceConfig', aceConfig
|
||||
if patchMe
|
||||
console.log 'setting me.heroConfig to', lastHeroConfig
|
||||
me.set 'heroConfig', lastHeroConfig
|
||||
me.patch()
|
||||
if patchSession
|
||||
console.log 'setting session.heroConfig to', sessionHeroConfig
|
||||
@options.session.set 'heroConfig', sessionHeroConfig
|
||||
@options.session.patch success: callback unless skipSessionSave
|
||||
else
|
||||
|
|
|
@ -11,6 +11,7 @@ LevelSchema.plugin(plugins.PermissionsPlugin)
|
|||
LevelSchema.plugin(plugins.VersionedPlugin)
|
||||
LevelSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
|
||||
LevelSchema.plugin(plugins.PatchablePlugin)
|
||||
LevelSchema.plugin(plugins.TranslationCoveragePlugin)
|
||||
|
||||
LevelSchema.post 'init', (doc) ->
|
||||
if _.isString(doc.get('nextLevel'))
|
||||
|
|
|
@ -9,5 +9,6 @@ ThangTypeSchema.plugin plugins.NamedPlugin
|
|||
ThangTypeSchema.plugin plugins.VersionedPlugin
|
||||
ThangTypeSchema.plugin plugins.SearchablePlugin, {searchable: ['name']}
|
||||
ThangTypeSchema.plugin plugins.PatchablePlugin
|
||||
ThangTypeSchema.plugin plugins.TranslationCoveragePlugin
|
||||
|
||||
module.exports = mongoose.model('thang.type', ThangTypeSchema)
|
||||
|
|
|
@ -35,6 +35,7 @@ ThangTypeHandler = class ThangTypeHandler extends Handler
|
|||
'rasterIcon'
|
||||
'featureImage'
|
||||
'spriteType'
|
||||
'i18nCoverage'
|
||||
]
|
||||
|
||||
hasAccess: (req) ->
|
||||
|
|
|
@ -281,7 +281,7 @@ module.exports.SearchablePlugin = (schema, options) ->
|
|||
|
||||
searchable = options.searchable
|
||||
unless searchable
|
||||
throw Error('SearchablePlugin options must include list of searchable properties.')
|
||||
throw new Error('SearchablePlugin options must include list of searchable properties.')
|
||||
|
||||
index = {}
|
||||
|
||||
|
@ -307,3 +307,19 @@ module.exports.SearchablePlugin = (schema, options) ->
|
|||
@index = @getOwner() unless access
|
||||
|
||||
next()
|
||||
|
||||
module.exports.TranslationCoveragePlugin = (schema, options) ->
|
||||
|
||||
schema.uses_coco_translation_coverage = true
|
||||
schema.set('autoIndex', true)
|
||||
|
||||
index = {}
|
||||
|
||||
if schema.uses_coco_versions
|
||||
if not schema.uses_coco_names
|
||||
throw Error('If using translation coverage and versioning, should also use names for indexing.')
|
||||
index.slug = 1
|
||||
|
||||
index.i18nCoverage = 1
|
||||
|
||||
schema.index(index, {sparse: true, name: 'translation coverage index', background: true})
|
|
@ -136,12 +136,14 @@ describe 'SegmentedSprite', ->
|
|||
segmentedSprite.tick(500)
|
||||
expect(segmentedSprite.baseMovieClip.currentFrame).toBe(6)
|
||||
|
||||
it 'emits animationend for animations where loops is false and there is no goesTo', ->
|
||||
it 'emits animationend for animations where loops is false and there is no goesTo', (done) ->
|
||||
fired = false
|
||||
segmentedSprite.gotoAndPlay('onestep')
|
||||
segmentedSprite.on('animationend', -> fired = true)
|
||||
segmentedSprite.tick(1000)
|
||||
expect(fired).toBe(true)
|
||||
_.defer -> # because the event is deferred
|
||||
expect(fired).toBe(true)
|
||||
done()
|
||||
|
||||
it 'scales rendered animations like a MovieClip', ->
|
||||
# build a movie clip, put it on top of the segmented sprite and make sure
|
||||
|
|
|
@ -150,3 +150,27 @@ describe 'CocoModel', ->
|
|||
else return ready false
|
||||
|
||||
request.response {status:200, responseText: JSON.stringify me}
|
||||
|
||||
describe 'updateI18NCoverage', ->
|
||||
class FlexibleClass extends CocoModel
|
||||
@className: 'Flexible'
|
||||
@schema: {}
|
||||
|
||||
it 'only includes languages for which all objects include a translation', ->
|
||||
m = new FlexibleClass({
|
||||
i18n: { es: {}, fr: {} }
|
||||
prop1: 1
|
||||
prop2: 'string'
|
||||
prop3: true
|
||||
innerObject: {
|
||||
i18n: { es: {}, de: {}, fr: {} }
|
||||
prop4: [
|
||||
{
|
||||
i18n: { es: {} }
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
m.updateI18NCoverage()
|
||||
expect(JSON.stringify(m.get('i18nCoverage'))).toBe('["es"]')
|
Loading…
Reference in a new issue